java设计模式——单例模式
1.饿汉式
线程安全,不管用不用都会创建对象,拿空间换时间。
/**
* 饿汉式
*/
public class Singleton {
private static Singleton instance = new Singleton ();
private Singleton () {}
public static Singleton getInstance() {
return instance;
}
}
2.懒汉式
进行一次非空判断,可能会出现一个或多个线程同时进入if语句,创建多个对象,线程不安全。
/** * 懒汉式 */ public class Singleton { private static Singleton instance; private Singleton () {} public static Singleton getInstance() { if(instance == null) {
instance = new Singleton();
}
return instance; } }
3.懒汉式同步锁版
虽然线程安全,但是锁范围较大,效率较低。
/**
* 懒汉线程同步锁版
*/
class Singleton {
private static Singleton instance;
private Singleton() {}
public synchronized static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
4.懒汉式双重检验锁版
依然存在问题instance = new Singleton()这行在JVM大致做了如下操作:
1.给instance分配内存
2.调用Singleton构造函数初始化成员变量
3.将instance对象指向分配的内存空间,执行完这一步,instance就不为null了
JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,所以此行不是一个原子操作
在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,最后报错。
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class){
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
5.懒汉式双重检验锁最终版
使用volatile关键字来解决上一版的问题,在这里volatile的作用是禁止JVM的指令重排序优化,而不是利用可见性。
/**
* 双重检验锁最终版
*/
public class Singleton{
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
6.静态内部类版
由于JVM特殊机制,线程安全,无效率缺陷,属于懒汉式。
//静态内部类版
public class Singleton { private static class SingletonHolder { private static Singleton INSTANCE = new Singleton (); } private Singleton () {} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; }
7.写法最简单的单例-枚举版
//枚举版 线程安全
public enum EasySingleton{ INSTANCE; }