19、Java并发-并发设计模式之单例模式

单例模式

单例对象的类必须保证只有一个实例存在。

许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为,比如全局信息配置。

1. 单例模式最简单的实现

public class Singleton {
	private Singleton() {
		System.out.println("Singleton is create");
	}
	private static Singleton instance = new Singleton();
	public static Singleton getInstance() {
		return instance;
	}
}

由私有构造方法和static来确定唯一性。

缺点:何时产生实例 不好控制

虽然我们知道,在类Singleton第一次被加载的时候,就产生了一个实例。但是如果这个类中有其他属性,比如:

public class Singleton {
	public static int STATUS=1; 
	private Singleton() {
		System.out.println("Singleton is create");
	}
	private static Singleton instance = new Singleton();
	public static Singleton getInstance() {
		return instance;
	}
}

当使用

System.out.println(Singleton.STATUS);

这个实例就被产生了。也许此时你并不希望产生这个实例。如果系统特别在意这个问题,这种单例的实现方法就不太好。

2. 第二种单例模式的解决方式(延迟加载)

public class Singleton {
	private Singleton() {
		System.out.println("Singleton is create");
	}
	private static Singleton instance = null;
	public static synchronized Singleton getInstance() {
		if (instance == null)
			instance = new Singleton();
		return instance;
	}
}

让instance只有在调用getInstance()方式时被创建,并且通过synchronized来确保线程安全,这样就控制了何时创建实例。

这种方法是延迟加载的典型。

但是有一个问题就是,在高并发的场景下性能会有影响,虽然只有一个判断就return了,但是在并发量很高的情况下,或多或少都会有点影响,因为都要去拿synchronized的锁。

3. 第三种方式(高效)

public class StaticSingleton {
	private StaticSingleton(){  
		System.out.println("StaticSingleton is create");
	}
	private static class SingletonHolder {
		private static StaticSingleton instance = new StaticSingleton();
	}
	public static StaticSingleton getInstance() {
		return SingletonHolder.instance;
	}
}

由于加载一个类时,其内部类不会被加载。这样保证了只有调用getInstance()时才会产生实例,控制了生成实例的时间,实现了延迟加载。并且去掉了synchronized,让性能更优,用static来确保唯一性。