Ensure a class has only one instance, and provide a global point of access to it.
确保某一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。
示例
饿汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton() { }
public static HungrySingleton instance() { return instance; }
public void say() { System.out.println("hello"); } }
|
懒汉式(加锁禁止重排序保证线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class LazySingleton {
private static volatile LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton instance() { if (instance == null) { synchronized (LazySingleton.class) { if (instance == null) { instance = new LazySingleton(); } } } return instance; }
public void say() { System.out.println("hello"); } }
|
当然Effective java推荐枚举式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public class EnumSingleton {
private EnumSingleton() { }
private enum Singleton { INSTANCE;
private final EnumSingleton instance;
Singleton() { instance = new EnumSingleton(); }
public EnumSingleton getInstance() { return instance; } }
public static EnumSingleton instance() { return Singleton.INSTANCE.getInstance(); }
public void say() { System.out.println("hello"); }
}
|
我选择静态内部类式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public class {
private () { }
private static class InstanceHolder { private final static NiceSingleton instance = new NiceSingleton(); }
public static NiceSingleton instance() { return InstanceHolder.instance; }
public void say() { System.out.println("hello"); }
}
|
疑问
当两个线程同时调用instance()方法时,由于singleton==null,两个线程都可以通过第一个校验,
然后线程A持有锁,线程B等待。当线程A执行完实例化、释放锁,线程B进入代码块。
如果不加第二个校验,线程B又会实例化一个对象。就会违反单例模式设计原则。
如果不加第一个校验,也能实现单例,但多个线程反复竞争锁会增加系统开销,严重影响性能。
近期评论