A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© forTomorrow 中级黑马   /  2015-6-4 19:32  /  1302 人查看  /  33 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

大家看看,为什么我加了同步,有时候程序运行也会出现不同步的情况呢
class RunImp implements Runnable {
    public static int count = 0;

    public  void run() {
        while (count < 5) {
            synchronized (this) {
               
                count++;
                System.out.println(Thread.currentThread().getName() + "--------"
                        + count);
            }
        }
    }
}

public class ThreadTest2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new Thread(new RunImp()).start();
        new Thread(new RunImp()).start();
    }

}
尝试很多次,有一次运行结果是这样的:
Thread-0--------2
Thread-0--------3
Thread-0--------4
Thread-0--------5
Thread-1--------2
大多情况都同步的

评分

参与人数 1技术分 +1 收起 理由
lwj123 + 1

查看全部评分

33 个回复

倒序浏览
  1. class RunImp implements Runnable {
  2.     public static int count = 0;

  3.     public  void run() {
  4.         while (count < 5)
  5.         {
  6.         /*1、假设 Thread-0 和Thread-1 在此时同时进入循环体内
  7.          * 2、这时Thread-0可能先获得锁,执行同步代码块中的买票过程。
  8.          * 当Thread-0 运行结束,而Thread-1 已经在循环体内了,没有在回去判断count的取值状态,
  9.          * 而是直接持有锁,执行买票过程,这就有可能造成线程不同步(对共享数据的操作出现偏差)
  10.          * 3、解决:在进入同步代码块内的时候在进行一次count 取值的判断,才能保证共享数据的唯一性
  11.          *           
  12.          * */
  13.             synchronized (this)
  14.             {  
  15.                     while(count<5)//进入同步代码块内在进行一次判断
  16.                     {
  17.                     count++;
  18.                 System.out.println(Thread.currentThread().getName() + "----"+ count);
  19.                     }
  20.             }
  21.         }
  22.     }
  23. }

  24. public class ThreadTest2 {

  25.     public static void main(String[] args) {
  26.         // TODO Auto-generated method stub
  27.         new Thread(new RunImp()).start();
  28.         new Thread(new RunImp()).start();
  29.     }

  30. }
复制代码

点评

额,明白了  发表于 2015-6-4 21:12
回复 使用道具 举报
。。路过  抢个沙发
回复 使用道具 举报
forTomorrow 来自手机 中级黑马 2015-6-4 21:51:25
板凳
想要那片海 发表于 2015-6-4 21:06

刚才洗澡时候想了下,你这方法的确解决了同步,避免了打印错误的结果6,但我的那个错误运行结果是怎么来的啊,静态变量啊,怎么没打印出1,反倒是2打印了两次
回复 使用道具 举报
视频刚看到这,晕呀。。
回复 使用道具 举报
好像是 线程都在抢先运行吧,不能按顺序是 狠正常的
回复 使用道具 举报
楼主对count用静态进行共享这能理解,但是楼主在建立多线程的时候,建立了两个对象,那么你所使用的锁的意义是什么,锁有起到作用?两个线程的运行的对象不是同一个
回复 使用道具 举报
探索者 发表于 2015-6-4 22:24
楼主对count用静态进行共享这能理解,但是楼主在建立多线程的时候,建立了两个对象,那么你所使用的锁的意 ...

对象不是同一个,但是count是静态的,只有一个啊.
他那个只要把synchronized拿到while外面就可以了
但是我运行是还是会出现2次2,而没有1的情况
刚不清楚是什么原因.百度中:dizzy:
回复 使用道具 举报
半月 发表于 2015-6-4 22:35
对象不是同一个,但是count是静态的,只有一个啊.
他那个只要把synchronized拿到while外面就可以了
但是我 ...

静态是不能解决同步问题的
回复 使用道具 举报
半月 发表于 2015-6-4 22:35
对象不是同一个,但是count是静态的,只有一个啊.
他那个只要把synchronized拿到while外面就可以了
但是我 ...

静态不能解决同步问题的
回复 使用道具 举报
半月 发表于 2015-6-4 22:35
对象不是同一个,但是count是静态的,只有一个啊.
他那个只要把synchronized拿到while外面就可以了
但是我 ...

这是我刚才按楼上提出的解决方案运行的结果:


回复 使用道具 举报
半月 来自手机 中级黑马 2015-6-4 23:15:48
12#
探索者 发表于 2015-6-4 22:56
这是我刚才按楼上提出的解决方案运行的结果:

找到问题了。new的是两个对象所以this是不一样的。锁不一样同步也就没有用了。把this改成class就可以了
回复 使用道具 举报

你好,你这样也不对!
他这里是this的问题,加同步锁是为了同一时刻只有一个对象在执行代码块,这里传this代表调用者,谁调用谁执行,所以不能保证同一时刻只有一个对象在执行代码块

解决办法:只需要改变锁对象即可(如:RunImp.class)
回复 使用道具 举报
探索者 发表于 2015-6-4 22:24
楼主对count用静态进行共享这能理解,但是楼主在建立多线程的时候,建立了两个对象,那么你所使用的锁的意 ...

恩,这个才是正解!:):)厉害
回复 使用道具 举报
半月 发表于 2015-6-4 22:35
对象不是同一个,但是count是静态的,只有一个啊.
他那个只要把synchronized拿到while外面就可以了
但是我 ...

这哥们是正解。你传的this,那个线程调用代表那个对吧,那就代表不同的对象。所以你这个不能保证同步。只需改变同步对象。
回复 使用道具 举报
武汉小菜鸟 发表于 2015-6-4 23:21
你好,你这样也不对!
他这里是this的问题,加同步锁是为了同一时刻只有一个对象在执行代码块,这里传thi ...

我比较赞同你的观点,我感觉也是this表示的是不同对象,所以导致不是同一把锁,改为类的字节码应该就可以,还没测试
回复 使用道具 举报
修改后的代码:

package com.itheima;

class RunImp implements Runnable {
        public static int count = 0;

        public  void run() {
                while (count < 5) {
                        synchronized (RunImp.class) {       
                                if(count>=5)
                                        break;
                                count++;
                                System.out.println(Thread.currentThread().getName() + "--------"
                                                + count);
                        }
                }
        }
}

public class ThreadTest2 {

        public static void main(String[] args) {
                // TODO Auto-generated method stub
                new Thread(new RunImp()).start();
                new Thread(new RunImp()).start();
        }

}
回复 使用道具 举报
实现方式二:

package com.itheima;

class RunImp implements Runnable {
        private int count = 0;
        public  void run() {
                while (count < 5) {
                        synchronized (RunImp.class) {       
                                if(count>=5)
                                        break;
                                count++;
                                System.out.println(Thread.currentThread().getName() + "--------"
                                                + count);
                        }
                }
        }
}

public class ThreadTest2 {

        public static void main(String[] args) {
                // TODO Auto-generated method stub
                RunImp runImp = new RunImp();
                new Thread(runImp).start();
                new Thread(runImp).start();
        }

}
回复 使用道具 举报
forTomorrow 发表于 2015-6-5 08:57
修改后的代码:

package com.itheima;

这个方式是不行的,建立的还是两个对象,虽然你用了唯一的字节码文件作为锁,但对于两个对象,就相对于有两把锁,每一个对象的锁都有唯一的钥匙,但由于不是在同一个对象运行,即使使用的锁为字节码文件,也起不到同步的作用。
回复 使用道具 举报
武汉小菜鸟 发表于 2015-6-4 23:21
你好,你这样也不对!
他这里是this的问题,加同步锁是为了同一时刻只有一个对象在执行代码块,这里传thi ...

如果建立的是两个对象,那么即使改变锁对象为唯一的字节码文件,也是起不到同步的作用
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马