实现方式
饿汉式(最简单的单例实现)
class Singleton { private static Singleton ourInstance = new Singleton(); private Singleton() { } public static Singleton newInstance() { return ourInstance; } }
懒汉式
class Singleton { private static Singleton ourInstance = null; private Singleton() { } public static Singleton newInstance() { if( ourInstance == null){ ourInstance = new Singleton(); } return ourInstance; } }
多线程下的单例模式实现
在多线程的情况下:
- 对于“饿汉式单例模式”:适用,因为JVM只会加载一次单例类;
- 对于“懒汉式单例模式”:不适用,因为“懒汉式”在创建单例时是线程不安全的,多个线程可能会并发调用 newInstance 方法从而出现重复创建单例对象的问题。
解决方案1:同步锁
使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成instance被多次实例化。
class Singleton { private static Singleton ourInstance = null; private Singleton() { } public static Singleton newInstance() { synchronized (Singleton.class){ if( ourInstance == null){ ourInstance = new Singleton(); } } return ourInstance; } }
解决方案2:双重校验锁
在同步锁的基础上( synchronized (Singleton.class) 外)添加了一层if,这是为了在Instance已经实例化后下次进入不必执行 synchronized (Singleton.class) 获取对象锁,从而提高性能。
class Singleton { private static Singleton ourInstance = null; private Singleton() { } public static Singleton newInstance() { if( ourInstance == null){ synchronized (Singleton.class){ if( ourInstance == null){ ourInstance = new Singleton(); } } } return ourInstance; } }
解决方案3:静态内部类
在JVM进行类加载的时候会保证数据是同步的,我们采用内部类实现:在内部类里面去创建对象实例。
只要应用中不使用内部类 JVM 就不会去加载这个单例类,也就不会创建单例对象,从而实现“懒汉式”的延迟加载和线程安全。
class Singleton { //在装载该内部类时才会去创建单例对象 private static class Singleton2{ private static Singleton ourInstance = new Singleton(); } private Singleton() { } public static Singleton newInstance() { return Singleton2.ourInstance; } }
解决方案4:枚举类型
最简洁、易用的单例实现方式,(《Effective Java》推荐)
public enum Singleton{ //定义一个枚举的元素,它就是Singleton的一个实例 instance; public void doSomething(){ } } //使用方式 Singleton singleton = Singleton.instance; singleton.doSomething();