单例模式(singleton pattern)真的是老生常谈了。本质上就是为了节省内存开销,希望尽可能减少对象创建数量,尤其是只用来做函数调用的对象。
单例模式分两种:懒汉式和饿汉式。补充一点,不管是哪种,都应该私有化构造函数强化单例性质。
A.懒汉式
关于懒汉式我真的不想说啥,这玩意线程安全问题太多了,多到都不想去用。直接上案例:
/**
* 懒汉式单例
*/
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
//1
if (singleton == null) {
//2
singleton = new LazySingleton();
}
return singleton;
}
}
好,上述是经典错误。线程安全问题。。A线程和B线程有可能同时进入2位置。。
改进一下:
/**
* 懒汉式单例
*/
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton() {
}
public synchronized static LazySingleton getInstance() {
//1
if (singleton == null) {
//2
singleton = new LazySingleton();
}
return singleton;
}
}
加了线程互斥锁,以性能为代价,保证线程安全,这个没毛病。然后就有强迫症程序员要优化了
/**
* 懒汉式单例
*/
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
synchronized (LazySingleton.class){
//1
if (singleton == null) {
//2
singleton = new LazySingleton();
}
}
return singleton;
}
}
改成了同步代码块,确实稍微好了点,但是有的童鞋还是不满意,于是有了接下来:
/**
* 懒汉式单例
*/
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
//0
if (singleton == null) {
synchronized (LazySingleton.class) {
//1
if (singleton == null) {
//2
singleton = new LazySingleton();
}
}
}
return singleton;
}
}
貌似叫啥子双重检测锁,好吧,感觉好复杂。事实上这个还是有问题。因为java的一些操作本身就不是原子性的,即对象生成和初始化分了好几步,有兴趣的童鞋可以去研究下。
然后是终极版:
/**
* 懒汉式单例
*/
public class LazySingleton {
private volatile static LazySingleton singleton = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
//0
if (singleton == null) {
synchronized (LazySingleton.class) {
//1
if (singleton == null) {
//2
singleton = new LazySingleton();
}
}
}
return singleton;
}
}
加了volatile关键字。。原理就不赘述了,有兴趣的童鞋可以自己查资料。。
扯远了,咱们不说那个恶心的懒汉式了。
B.饿汉式
写法很多,举个栗子:
/**
* 饿汉式单例
*/
public class HungarySingleton {
private static HungarySingleton singleton = new HungarySingleton();
public static HungarySingleton getInstance() {
return singleton;
}
private HungarySingleton() {
}
}
当然有人把声明和初始化分开的,都无所谓,用的是类加载线程互斥的原理。
接下来说一个最好的饿汉式单例实现:
/**
* 饿汉式单例
*/
public enum HungarySingleton {
singleton
}
单枚举的枚举类,最佳实现,没有之一
总结:
(1)单例主要是为了节省内存开销
(2)如果没有啥特殊要求,就用饿汉式吧。。。