标签:
单例模式确保一个类只有一个实例,并提供一个全局访问点。
有如下几种实现单例模式的方法:
使用“急切”创建实例,而不用延迟实例化的做法。在静态初始化器中创建单例,保证了线程安全。
public class Singleton { // √ private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } }
class Singleton2 { private static Singleton2 instance; private Singleton2() {} public static synchronized Singleton2 getInstance() { if (instance == null) { instance = new Singleton2(); } return instance; } }
同步getInstance()的做法将拖垮性能(同步一个方法可能造成程序执行效率下降100倍),一般不采用这种做法。
class Singleton3 { // √ , 比 Singleton2 好 private volatile static Singleton3 instance; private Singleton3() { } public static Singleton3 getInstance() { if (instance == null) { synchronized(Singleton3.class) { if (instance == null) { instance = new Singleton3(); } } } return instance; } }
volatile关键词确保:当instance变量被初始化成Singleton3实例时,多个线程正确地处理instance变量。
Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。
(1) 一个变量经 volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值;
(2) 看下面的一段代码:
private int i3; synchronized int geti3() {return i3;}
首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行。
但是,synchronized也同步内存:事实上,synchronized在“主”内存区域同步整个线程的内存。因此,执行geti3()方法做 了如下几步:
1>. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放)
2>. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗])
3>. 代码块被执行
4>. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值)
5>. 线程释放监视this对象的对象锁
标签:
原文地址:http://www.cnblogs.com/xwz0528/p/4779007.html