) { return Singleton3.Singleton3Handler.instance3; } }
第二种:使用枚举方式 优点: 线程是安全的
public enum Singleton4{ INSTANCE; public void method() { //TODO } } 在任何情况下,它都是一个单例 我们可以直接 Singleton4.INSTANCE 引用
第三种:使用DCL模式 需要使用Volatile 关键字 双重锁懒汉式( Double Check Lock 简称 DCL ) 优点:只有对象需要被使用的时候才创建,第一次判断instance21 == null 为了避免非必要枷锁,当第一次加载时才对实例进行枷锁在实例化。这样就可以节约内存空间,有可以保证线程安全。
缺点:但是,由于jvm存在乱序执行功能,DCL也会出现线程不安全的情况。
比如: instance21 = new Singleton2; 这个步骤,其实在jvm里面的执行分为三步: 1:在堆内开辟内存空间 2;在堆内存中实例化Singleton2里面的各个参数 3: 把对象指向堆内存 但是这个缺点在jdk1.6以后 只需要定义 为: private volatile static Singleton5 instance5 = null; 就可以 解决此问题 。 volatile确保instance每次在均在主内存中读取,这样虽然会牺牲一点效率。
public class Singleton5{ // 对象一实例 private volatile static Singleton5 instance5; //私有构造器 private Singleton5() { } //DCL懒汉式 public static Singleton5 getInstance() { if(instance5==null) { synchronized(Singleton5.class){ if(instance5 == null) { instance5 = new Singleton5(); } } } return instance5; } }
需要注意的是:
需要延迟加载的情况下使用第一、第二种;
需要防止序列化问题、反射攻击使用第三种。
才疏学浅,如有错误,恳请指教!
|