//代码引自Java设计模式,我自己稍有改动 public class Factory{ private static Factory factory; private long wipMoves; private Factory(){ wipMoves=0; } public static Factory getFactory(){ synchronized(Factory.class){//这里能不能用this??? if(factory==null) factory=new Factory(); return factory; } } }
Java中,不能在static 方法中使用this:http://www.cnblogs.com/EvanLiu/archive/2013/06/05/3118420.html
感觉那个例子不是很好哇,http://my.oschina.net/u/866190/blog/205454这个分析还是比较好的
很多人熟知单例模式中有一种写法是使用双重检查锁实现的,但是在网上看到的例子基本上都不正确,有些写是正确,但没有很好解析,造成很多人没有真正理解。其中,典型错误写法是这样的:
1 public class Resource { 2 3 private static Resource resource ; 4 5 public static Resource getInstance(){ 6 7 if(resource == null ){ 8 synchronized (Resource.class) { 9 if(resource == null ){ 10 resource = new Resource() ; 11 } 12 } 13 14 } 15 16 return resource ; 17 } 18 19 private Resource(){} 20 21 }
它基本思路是,首先在没有同步的情况下检查resource是否等于null,如果条件不成立,直接返回resource 。否则,就使用同步再检查resource是否等于null,条件成立才正真初始化resource。这中方式既保证只有一个线程初始化resource,又能做到延时加载。似乎是“鱼和熊掌可兼得“。
上面程序真正的问题是没有同步的情况下读取共享变量resource,并发的情况下对象的状态值有可能是过期无效的。要解决这个问题也很简单,把resource声明为volatile类型。volatile有什么作用?引用《java并发编程实战》的解析:
当一个域声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。
volatile变量不会缓存在寄存器或缓存在对其他处理器隐藏的地方。所以,读一个volatile类型的变量时,总会返回由某一线程所写入的最新值。
读取volatile变量比读取非volatile变量的性能几乎没有差别,不过需要注意的是volatile只能保证内存可见性,并不能保证原子性。
所以嘛,这个是双重检查锁中最好的代码(代码引自维基百科)
1 public class Singleton { 2 private static volatile Singleton INSTANCE = null; 3 4 // Private constructor suppresses 5 // default public constructor 6 private Singleton() {} 7 8 //thread safe and performance promote 9 public static Singleton getInstance() { 10 if(INSTANCE == null){ 11 synchronized(Singleton.class){ 12 //when more than two threads run into the first null check same time, to avoid instanced more than one time, it needs to be checked again. 13 if(INSTANCE == null){ 14 INSTANCE = new Singleton(); 15 } 16 } 17 } 18 return INSTANCE; 19 } 20 }
维基百科真好,再看看这个:http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F#Java.E4.B8.AD.E7.9A.84.E4.BD.BF.E7.94.A8
(维基百科,饿汉方式)
public class Singleton { private final static Singleton INSTANCE = new Singleton(); // Private constructor suppresses private Singleton() {} // default public constructor public static Singleton getInstance() { return INSTANCE; } }
http://www.cnblogs.com/techyc/p/3529983.html中说
根据Java Language Specification,JVM本身保证一个类在一个ClassLoader中只会被初始化一次。那么根据classloader的这个机制,我们在类装载时就实例化,保证线程安全。
但是,有些时候,这种创建方法并不灵活。例如实例是依赖参数或者配置文件的,在getInstance()前必须调用某些方法设置它的参数。
http://www.cnblogs.com/techyc/p/3529983.html中也说了单例模式失效的场景
http://blog.csdn.net/haoel/article/details/4028232中说明对失效情况进行了分析
Effective Java作者Josh Bloch 提倡的是用枚举
还有其他方法,参看:
http://zh.wikipedia.org/wiki/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F
http://blog.csdn.net/haoel/article/details/4028232
http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
通常单例模式在Java语言中,有两种构建方式:(维基百科)
双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。(维基百科)
说了这么多,还不知道什么情况下使用单例模式呢,如果让举个例子,怎么说呢
http://blog.csdn.net/csh624366188/article/details/7465505看看这个,虽然不是我想要的结果
登记式单例类 登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。(http://www.javaarch.net/jiagoushi/557.htm,博主应该是阿里的人,先膜拜一把)“饿汉式单例类及懒汉式单例类均不可继承”这句话不懂唉,还说“java.lang.Runtime 典型的单例模式”
这些下次看这个时再找资料补充吧
原文:http://www.cnblogs.com/crane-practice/p/3660119.html