这两天在看开源项目时,发现Event Bus和Universalimageloader中写单例模式都是Double Check的形式。平时总是看到各种各样的单例模式,如,饿汉式,懒汉式等等。其中大多存在问题。今天记录一种比较优秀的单例模式的写法------Double Check。以后我准备就用这种方法了。(虽然还有其他优秀的方式,比如内部静态类,枚举)
先上代码:
public class ImageLoader { private volatile static ImageLoader instance; // Returns singleton class instance public static ImageLoader getInstance() { if (instance == null) { synchronized (ImageLoader.class) { if (instance == null) { instance = new ImageLoader(); } } } return instance; } }
这是EventBus中的代码。其中两次检查是否instance == null,第一个是为了避免每次都加锁,毕竟这有一定的开销。第二个是为了避免同步问题,比如十个线程同时调用getInstance()方法,都执行了第一步检查instance == null,并且其中一个线程成功获得了锁(执行了synchronized语句),接下来如果没有再一次判断instance == null,则十个线程将生成10对象,这违背了单例的初衷。
上述代码除了有两次检查instance == null,另一个特点是变量instance的类型声明中添加了volatile,因为像下面这种创建对象的语句并不是原子操作,volatile可以使其成为原子操作,避免同步问题。
instance = new ImageLoader();
虽说部分JVM没有完全volatile,但是目前主流的JVM貌似已经都支持了,所以这个问题一般可以忽略。
参考:
http://www.zhihu.com/question/29971746
https://www.v2ex.com/t/193589#reply15
时间: 2024-11-10 01:19:53