黑马程序员技术交流社区

标题: 这个懒汉式我会写,如何用代码证明写了同步和没有写同步之间的区别呢 [打印本页]

作者: dsh    时间: 2014-10-10 21:53
标题: 这个懒汉式我会写,如何用代码证明写了同步和没有写同步之间的区别呢
package Thread_Single01;
//懒汉式,这里要使用延迟加载技术,和多线程技术
public class Single2 {
        private Single2() {//为了保证数据的唯一型
                super();
                // TODO Auto-generated constructor stub
        }
       
        static Single2 s= null;//由于get方法返回的是s  所以s也要静态,要不然又get时 s还没有出现
       
        public synchronized static Single2 getInstance(){//由于构造函数被私有,只能用类名调用,类名只能调用静态方法
                if(s==null){
                        s= new Single2();       
                }
                return s;
        }
}
作者: 980344791    时间: 2014-10-10 22:10
只学过饿汉,懒汉看不懂;。。
作者: 香草芭芙    时间: 2014-10-10 22:28
  1. class LazySingleton
  2. {
  3.         private static LazySingleton ls = null;
  4.         private LazySingleton(){}
  5.         private static LazySingleton getInstance()
  6.         {
  7.                 if (ls == null) //用双重判断提高效率.
  8.                 {
  9.                         synchronized (LazySingleton.class) //同步就加锁, 不同步就没锁,可能会出现大于1对象的情况,
  10.                         {
  11.                                 if (ls == null)
  12.                                 {
  13.                                         ls = new LazySingleton();
  14.                                 }
  15.                         }
  16.                 }
  17.                 return ls;
  18.         }
  19. }
复制代码

作者: dsh    时间: 2014-10-10 22:34
香草芭芙 发表于 2014-10-10 22:28

美女   可以问问  你这的双重判断  是在避免什么问题出现  呢  好像视屏里看过,一时没有想起来
作者: dsh    时间: 2014-10-10 22:38
香草芭芙 发表于 2014-10-10 22:28

还有个问题  你的这个代码是怎吗弄成这样的,教教我    我每次都是复制的   很想知道你这是怎么弄的
作者: ifinver    时间: 2014-10-10 23:24
本帖最后由 ifinver 于 2014-10-10 23:26 编辑

没同步的代码是这样
  1. public static NoSingle getInstance(){
  2.                 if(ns == null){
  3.                         ns = new NoSingle();
  4.                 }
  5.                 return ns;
  6.         }
复制代码
是第一个线程执行到if(ns==null)的里面,但又没执行ns=new NoSingle()的一瞬间被CPU切换出去,第二个线程进来执行一边,给ns付了值,第一个线程切换回来继续执行,就会产生一个新的NoSignle对象返回,失去了单例的意义。想要验证的话可以人为的让线程在if(ns==null)与ns=new NoSingle()之间停一停,放大这个时间差,然后验证之,经过验证,不加同步区别巨大=。=
我这么验证的:
  1. //没加同步的"单例"类
  2. public class NoSingle {
  3.         private static NoSingle ns = null;
  4.         private NoSingle(){}
  5.        
  6.         public static NoSingle getInstance(){
  7.                 if(ns == null){
  8.                         //人为的让进来的每个线程在这里停一停
  9.                         //做个循环消磨一下时间
  10.                         for(int i = 0; i < 10000; i ++){
  11.                                 int x = i + 1;
  12.                         }
  13.                         //这个是原本要同步的关键代码
  14.                         ns = new NoSingle();
  15.                 }
  16.                 return ns;
  17.         }
  18. }
复制代码



主函数:
  1. public class Test {
  2.         
  3.         public static void main(String[] args) throws InterruptedException{
  4.                
  5.                 //定义10个TestThread对象
  6.                 TestThread[] tt = new TestThread[10];
  7.                 for(int i = 0;i < 10;i ++){
  8.                         tt[i] = new TestThread();
  9.                 }
  10.                 //分别用10个TestThread对象构建10个线程
  11.                 //意思就是10个"NoSingle.getInstance()"语句同时执行
  12.                 Thread[] ts = new Thread[10];
  13.                 for(int i = 0;i < 10;i ++){
  14.                         ts[i] = new Thread(tt[i]);
  15.                 }
  16.                 //开启10个线程
  17.                 for(int i = 0;i < 10;i ++){
  18.                         ts[i].start();
  19.                 }
  20.                 //等待3S以确认10个线程都执行完并且结束了
  21.                 Thread.sleep(3000);
  22.                
  23.                 //然后对比tt数组中的10个对象,每个对象中都存有一个NoSingle类的引用
  24.                 //“引用”就是c++中的指针,可以直接比较,指向同一个对象则“引用”相等
  25.                 //如果10个对象中有1个中NoSingle的引用与其他不一样,意思就是单例设计模式没单例成功
  26.                 //则证明没有同步是不安全的
  27.                 boolean b = true;
  28.                 for(int i = 0; i < 9;i ++){
  29.                         if(tt[i].getRefrence() != tt[i+1].getRefrence()){
  30.                                 System.out.println("没同步代码不安全");
  31.                                 b = false;
  32.                         }
  33.                 }
  34.                 if(b){
  35.                         System.out.println("没同步代码好像没什么区别");
  36.                 }
  37.                
  38.         }
  39. }
  40. //多线程类,类中定义了一个NoSingle的变量,线程结束后,成员变量ns就拿到了一个NoSingle实例
  41. class TestThread implements Runnable{
  42.         private NoSingle ns;
  43.         @Override
  44.         public void run() {
  45.                 // TODO Auto-generated method stub
  46.                 ns = NoSingle.getInstance();
  47.         }
  48.         public NoSingle getRefrence(){
  49.                 return ns;
  50.         }
  51.         
  52. }
复制代码






作者: dsh    时间: 2014-10-11 00:47
ifinver 发表于 2014-10-10 23:24
没同步的代码是这样是第一个线程执行到if(ns==null)的里面,但又没执行ns=new NoSingle()的一瞬间被CPU切换 ...

非常感谢   解释的非常详细
作者: HM2014nuli    时间: 2014-10-11 07:13
本帖最后由 HM2014nuli 于 2014-10-11 07:29 编辑

如果在懒汉式s=new Single2();上面加一句Thread.sleep(10),你就会发现问题了,但你加同步时,如果加在函数上面又会出现一个新问题,就是在多线程执行它的情况下,造成每个线程都要去判断一下,很是消耗资源,所以这时你应该把函数上的同步去掉,在if(s==null)下面加一个同步块,锁是本类的字节码对象,在锁里再进行判断,如果null。就进行s=new Single2();并在第一个判断外面对外return s;新人一个希望能帮到你




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2