单例模式

//代码引自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.youkuaiyun.com/haoel/article/details/4028232中说明对失效情况进行了分析

 

Effective Java作者Josh Bloch 提倡的是用枚举

http://www.importnew.com/6461.html这个写的好:

1 public enum Singleton{
2     INSTANCE;
3 }

很神奇,关于枚举《effective java》中有介绍,还有这个链接:http://www.ibm.com/developerworks/cn/java/j-lo-enum/

 

还有其他方法,参看:

http://zh.wikipedia.org/wiki/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F

http://blog.youkuaiyun.com/haoel/article/details/4028232

http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html

 

通常单例模式在Java语言中,有两种构建方式:(维基百科)

  • 懒汉方式(延迟加载)。指全局的单例实例在第一次被使用时构建。
  • 饿汉方式(非延迟加载)。指全局的单例实例在类装载时构建。

双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。(维基百科)

 

说了这么多,还不知道什么情况下使用单例模式呢,如果让举个例子,怎么说呢

http://blog.youkuaiyun.com/csh624366188/article/details/7465505看看这个,虽然不是我想要的结果

登记式单例类 登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。(http://www.javaarch.net/jiagoushi/557.htm,博主应该是阿里的人,先膜拜一把)“饿汉式单例类及懒汉式单例类均不可继承”这句话不懂唉,还说“java.lang.Runtime 典型的单例模式”

这些下次看这个时再找资料补充吧

 

 

还有一种方法也比较好,是用静态内部类实现的:http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html

 1 public class Singleton {
 2 
 3     private Singleton() {
 4 
 5     }
 6     
 7     private static class SingletonHolder {
 8         private static Singleton instance = new Singleton();
 9     }
10 
11     public static Singleton getInstance() {
12         return SingletonHolder.instance;
13     }
14 }

 

解释一下,因为java机制规定,内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的(实现线程安全)。内部类加载的时候实例化一次instance。

 

 这个博客写的好 : http://www.chenyudong.com/archives/java-singleton.html#i-2

 

 

转载于:https://www.cnblogs.com/crane-practice/p/3660119.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值