单例模式常见的实现方式有懒汉式和饿汉式两种(不知道谁发明的这糙名字emm...)直接贴代码如下:
1.Eagerly initialized
1 /** 2 * 不可变类其实例不能被修改; 不可变对象,本质上是线程安全的; 3 */ 4 public final class EagerlyMan { 5 // 将域定义为final,可以确保对实例的引用在线程传递中的不可变 6 private static final EagerlyMan INSTANCE = new EagerlyMan(); 7 8 private EagerlyMan() {} 9 10 // 使用静态工厂取代导出公有的静态final域,可以提供更多的灵活性 11 public static EagerlyMan getInstance() { return INSTANCE; } 12 13 }
1. static 关键字可以起到两个重要作用:
①、方便类在没有创建对象的情况下调用方法或字段(必须是static的);
②、被static修饰的字段或代码块当且只当类加载的时候就初始化,static字段在内存中只有一个副本,被所有的对象共享
2. Lazily initialized需要同步机制
1 public final class LazyMan { 2 3 private static LazyMan instance; 4 5 private LazyMan() { 6 if (instance != null) { 7 // 享有特权的客户端可以调用AssessibleObject.setAccessinle方法通过反射调用私有构造器,为抵御这种方式可以抛出一个异常 8 throw new IllegalStatExcaption(); 9 } 10 } 11 // 避免延迟初始化产生的竞态条件,使用同步代码块保证原子性和可见性 12 public static synchronized LazyMan getInstance() { 13 if (instance == null) { 14 instance = new LazyMan(); 15 } 16 return instance; 17 } 18 }
在这两种习惯模式中(正常初始化和延迟初始化)应用到非静态域上也是一样的
3. 双重检查初始化
1 public final class SuperLazyMan { 2 3 private volatile SuperLazyMan instance; 4 5 private SuperLazyMan() { 6 if (instance != null) { 7 throw new IllegalStateException(); 8 } 9 } 10 11 public SuperLazyMan getInstance() { 12 // 线程私有的局部变量, 确保实例域被初始化后只读取一次,可以提升性能 13 SuperLazyMan result = instance; 14 15 if (result == null) { 16 synchronized (this) { 17 result = instance; 18 if (result == null) { 19 /** 这段是非原子操作,大致做了3件事情: 20 * 1.给实例分配内存 2.构造器初始化 3.将instance对象指向分配的内存空间 21 * 由于指令的重排序,3可能会在2之前执行, 因此instance必须加上volatile,禁止指令重排序 22 */ 23 result = instance = new SuperLazyMan(); 24 } 25 } 26 } 27 return result; 28 } 29 }
4.使用内部类延迟初始化
1 public final class DemandHolderLazyMan { 2 3 private DemandHolderLazyMan() {} 4 5 public static DemandHolderLazyMan getInstance() { 6 return HelperHoler.INSTANCE; 7 } 8 9 private static class HelperHoler { 10 11 private static final DemandHolderLazyMan INSTANCE = new DemandHolderLazyMan(); 12 } 13 }
总结:
大多数的域都应该正常地进行初始化,而不是延迟初始化。如果是为了达到性能目标而必须延迟初始化一个域,对于实例域,就使用双重检查模式;对于静态域,则使用内部类延迟初始化。
—————— 摘自Joshua Bloch "Effective Java, Second Edition"