设计模式学习笔记(单例模式篇)

单例模式的定义:

确保一个类只有一个实例,并提供一个全局访问点。

懒汉式

public class SingleTon {
	private static SingleTon instance;
	public static SingleTon getInstance() {
		if (null == instance) {
			instance = new SingleTon();
		}
		return instance;
	}
}

私有化了构造函数,并对外提供获取实例对象的共有方法。所谓懒汉式,就是用到的时候才会真正的去创建对象。
优点:可以实现延时加载
缺点:在多线程并发访问的情况下,会有线程安全问题。

那么如何解决线程安全问题?我们首先想到的就是加锁,在getInstance方法上加上synchronized关键字。

public class SingleTon {
	private static SingleTon instance;
	public static synchronized SingleTon getInstance() {
		if (null == instance) {
			instance = new SingleTon();
		}
		return instance;
	}
}

加锁能解决线程安全问题,但是会导致性能下降很多。并且只有在第一次访问的时候才会真正用到锁。

我们刚解决了一个问题,却又必须面对性能下降的巨大压力。那么该怎么办呢?解决的办法就是使用双重检查加锁

public class SingleTon {
	private static SingleTon instance;
	public static SingleTon getInstance() {
		if (instance == null) {
			synchronized(SingleTon.class) {
				if (instance == null) {
					instance = new SingleTon();
				}
			}
		}
		return instance;
}

性能上会有很大的提升,线程安全的问题解决了。那么还有其他的方案吗?答案肯定是有的,那就是使用静态内部类

package com.liwen.singleton;
public class SingleTon3 {
	/*
	 * 私有化构造函数
	 */
	private SingleTon() {
	}
	public static SingleTon getInstance() {
		return UserSingleTon.INSTANCE;
	}
	//静态内部类
	private static class UserSingleTon{
		private static final SingleTon INSTANCE = new SingleTon3();
	}
}

因为这个类的实例化是靠静态内部类的静态常量实例化的。INSTANCE 是常量,因此只能赋值一次;它还是静态的,因此随着内部类一起加载。采用静态内部类实现的代码也是懒加载的,只有第一次使用这个单例的实例的时候才加载, 同时不会有线程安全问题。

饿汉式

public class SingleTon {
	private static SingleTon instance = new SingleTon();
	public static SingleTon getInstance() {
		return instance;
	}
}

所谓的饿汉式,就是类加载的时候就会生成实例对象。

为什么使用单例?

优点

1、单例,也即是只有一个对象,尤其是对于一些很笨重的对象,本身不会变化,创建和销毁却又很消耗系统资源。那么我们很常见的做法就是在系统启动的时候就把这些对象创建好,并且做成单例供系统调用。
2、单例提供了一个全局访问点,和全局变量一样方便,却没有全局变量的缺点。
3、可以实现延迟实例化。

缺点

1、单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
2、单例对象如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。
3、一定程度上违反了“单一职责”。

单例的使用场景

常见应用场景

读取配置文件、加载工厂(JDBC)、线程池、日志等等。

你可能感兴趣的:(Java设计模式)