java 实现单例的各种方式

2017-03-21 19:59:37   最后更新: 2017-03-21 19:59:37   访问数量:187




上一篇日志中,我们介绍了单例模式的概念和基础的应用

单例模式 -- Singleton

本节中,我们就来介绍一下 java 语言中如何编写单例模式类

 

public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }

 

 

这是单例模式的最简单实现,private 的构造方法保证了类不会被通过 new 的方式创建,同时,判断 instance 是否为 null 保证了单线程环境下单例模式运行的正确性

但是,正如我们反复强调的,这种方式是非线程安全的,原因在于,当多个线程并发执行,同时进行判断 instance 为 null 的操作,而此时 instance 确实为 null,那么所有的线程都将去创建一个单例的对象,这显然是我们不希望看到的,那么下面我们就来解决这个问题

 

正如上面提到的,之所以存在线程安全问题,主要是因为判断 instance 是否为 null 与对象的创建是非原子性的,那么,我们只需要用锁来保证两个操作的原子性即可解决这个问题

public class Singleton { private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

 

但是加锁对性能是会造成影响的,在并发环境下,当一个线程运行到 synchronized 处,获取锁进入到 instance 的判断,其他所有的并发线程都必须在该线程执行完 instance 的创建操作后才能够继续执行,而事实上,一旦 instance 被创建,这样的等待都将会是白费的

 

双重校验锁对上面的例子进行了优化

public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }

 

一旦对象被创建,那么程序将不会去请求获取锁而是直接返回 instance

 

public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }

 

这段代码看上去非常简单,他会在类首次被加载时创建单例的对象,jvm 会保证单例对象只被创建一次,但是有时我们仅仅是在代码中引用了这个类,或者仅仅调用了这个类中的其他方法,我们并不希望在我们还不需要通过 getInstance 方法获取对象的时候,对象就已经被创建了,这是这种方式的主要问题

 

public class Singleton { private Singleton() { } private static class SingletonHolder { private final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }

 

这种方式解决了上一种方式所存在的问题,仅在 getInstance 方法被调用时,对象才会被创建

 

public enum SingletonEnum { BOOM_MAZE_FACTORY(new BoomMazeFactory()), STANDARD_MAZE_FACTORY(new StandardMazeFactory()), ; private MazeFactory mazeFactory; public MazeFactory getMazeFactory() { return mazeFactory; } SingletonEnum(MazeFactory mazeFactory) { this.mazeFactory = mazeFactory; } }

 

 

由于枚举在项目中并不会被常常用到,这样的用法就更加难得一见了,而事实上,这才是最推荐的用法

 






技术帖      技术分享      java      singleton      设计模式      模式      设计      单例     


京ICP备15018585号