设计模式之单例模式(线程安全)

设计模式之单例模式(线程安全)

可以说单例模式是所有设计模式中最简单的一种。

单例模式就是说系统中对于某类的只能有一个对象,不可能出来第二个。

单例模式也是23中设计模式中在面试时少数几个会要求写代码的模式之一。主要考察的是多线程下面单例模式的线程安全性问题

1.多线程安全单例模式实例一(不使用同步锁)

复制代码
1 public class Singleton {
2     private static Singleton sin=new Singleton();    ///直接初始化一个实例对象
3     private Singleton(){    ///private类型的构造函数,保证其他类对象不能直接new一个该对象的实例
4     }
5     public static Singleton getSin(){    ///该类唯一的一个public方法    
6         return sin;
7     }
8 }
复制代码

  上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。 

2.多线程安全单例模式实例二(使用同步方法)

复制代码
 1 public class Singleton {  
 2      private static Singleton instance;  
 3      private Singleton (){
 4          
 5      }   
 6      public static synchronized Singleton getInstance(){    //对获取实例的方法进行同步
 7        if (instance == null)     
 8          instance = new Singleton(); 
 9        return instance;
10      }
11  }  
复制代码

  上述代码中的一次锁住了一个方法, 这个粒度有点大 ,改进就是只锁住其中的new语句就OK。就是所谓的“双重锁”机制。

3.多线程安全单例模式实例三(使用双重同步锁)

复制代码
 1 public class Singleton {  
 2      private static Singleton instance;  
 3      private Singleton (){
 4      }   
 5      public static Singleton getInstance(){    //对获取实例的方法进行同步
 6        if (instance == null){
 7            synchronized(Singleton.class){
 8                if (instance == null)
 9                    instance = new Singleton(); 
10            }
11        }
12        return instance;
13      }
14      
15  }
复制代码
分类:  设计模式
3
0
« 上一篇: Aho-Corasick 多模式匹配算法、AC自动机详解
» 下一篇: Horspool 字符串匹配算法

posted on 2013-11-21 09:33 旭东的博客 阅读(37371) 评论(7编辑 收藏

评论

#1楼   回复引用

方法三比方法二好在哪里?
2013-11-21 15:40 |  江海不系舟   

#2楼[楼主]   回复引用

@ cctw
方法二锁定整个方法块,方法三只是锁定了方法中的一个代码段。只是锁的“粒度”不同吧。
2013-11-21 18:41 |  旭东的博客   

#3楼   回复引用

并没有注意到用双重锁时会产生指令重排的情况
2016-06-04 16:24 |  贴地   

#4楼   回复引用

为什么要两次判断instance == null?
2016-10-06 10:50 |  gschen   

#5楼   回复引用

回复4楼的兄弟,为什么要两次判断instance == null,android应用跑起来是要开一个主线程和若干条子线程的,假如这里有A和B两条子线程都想执行这个单例模式的代码,假如A线程抢到了执行权,执行到第6行的判断语句if (instance == null),这时候instance是为空的,就进入了方法体里面,就在快要进入同步代码块的时候恰巧B线程把执行权抢走了,这时候B线程要执行第6行的判断语句if (instance == null),因为之前A线程没有进入同步代码块,instance没有创建成功,这时候instance依然为空,所以instance == null为true,B线程也会进入方法体里面去执行同步代码块,而恰巧这时候A线程突然夺过执行权先于B线程进入同步代码块,这时候B线程只有等A线程从同步代码块中出来才有机会进入同步代码块执行里面的逻辑.A线程进入同步代码块执行里面的代码,A线程执行完instance 对象被创建出来了,这时候B线程也如愿的抢到了执行权,你说这时候B线程要不要判断instance是否为空呢?如果不做判断那就直接又创建了一个对象,所以需要先判断instance是否为空再决定需不需要创建instance对象,其实这里问题不大,我假设的这种情况很少出现,而且只会在第一次初始化instance实例的时候才有可能出现这种情况,造成的影响就是多创建了一个对象,而且这个对象很快就会第二次创建的对象给替换覆盖掉而变成垃圾,具体到项目中会不会报异常这个我还不清楚,个人感觉应该不会.
2016-10-27 23:03 |  小菜牛   

#6楼   回复引用

如有对所机制不明白的, java锁机制
2017-03-23 11:28 |  wwwduyang   

#7楼   回复引用

@ 小菜牛
引用 回复4楼的兄弟,为什么要两次判断instance == null,android应用跑起来是要开一个主线程和若干条子线程的,假如这里有A和B两条子线程都想执行这个单例模式的代码,假如A线程抢到了执行权,执行到第6行的判断语句if (instance == null),这时候instance是为空的,就进入了方法体里面,就在快要进入同步代码块的时候恰巧B线程把执行权抢走了,这时候B线程要执行第6行的判断语句if (instance == null),因为之前A线程没有进入同步代码块,instance没有创建成功,这时候instance依然为空,所以instance == null为true,B线...

可以这么理解,如果只是如下代码,也可达到线程安全的,只是每次获取该对象时都要锁一次类对象耗费资源,为了避免每次都锁类对象,在之前再次判断对象是否为null
synchronzied(Singleton.class) {
if (instance == null){
instance = new Singleton(); 
}
}
2017-03-23 11:32 |  wwwduyang   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值