为什么把IF放到synchronized里面没事,但是放到线程外面就会发现有卡死(死锁)现象,逻辑上是不是出现问题,希望个位指点一下。。
class Bread
{
String name = "起司";
int count=0;
boolean flag = false;
}class Maker implements Runnable
{
Bread s ;
Maker(Bread s)
{
this.s = s;
}
public void run()
{
while(true)
{
synchronized(s)
{
if(!s.flag)
{
s.count++;
           System.out.println("面包师傅生产了"+s.name+"........"+s.count);
s.flag = true;

}
}
}
}
}class Consumer implements Runnable
{
Bread s ;
Consumer(Bread s)
{

this.s = s;
}
public void run()
{
while(true)
{
synchronized(s)
{
if(s.flag)
{

解决方案 »

  1.   

    这个代码没问题,就是把IF放到synchronized就有问题了。这里出现死锁
      

  2.   

    这个代码与上面代码比较,该代码会出现死锁。这是为什么呢。
    class Bread
    {
    String name = "起司";
    int count=0;
    boolean flag = false;
    }class Maker implements Runnable
    {
    Bread s ;
    Maker(Bread s)
    {
    this.s = s;
    }
    public void run()
    {
    while(true)
    {
    if(!s.flag)
    {
    synchronized(s)
    {
    s.count++;
    System.out.println("面包师傅生产了"+s.name+"........"+s.count);
    s.flag = true;
    }
    }
    }
    }
    }class Consumer implements Runnable
    {
    Bread s ;
    Consumer(Bread s)
    {
    this.s = s;
    }
    public void run()
    {
    while(true)
    {
    if(s.flag)
    {
    synchronized(s)
    {
    System.out.println("胖子消费了"+s.name+"........"+s.count);
    s.count--;
    s.flag = false;
    }
    } }
    }
    }class  Test
    {
    public static void main(String[] args) 
    {
    Bread s = new Bread();
    Maker a = new Maker(s);
    Consumer b = new Consumer(s);
    Thread t = new Thread(a);
    Thread t2 = new Thread(b);
    t.start();
    t2.start();
    }
    }
      

  3.   

    你需要用到wait()和notifyall去控制线程用共享的资源。当你的一个线程更新了flag,而另一个线程无法更新的时候,就会卡住了
      

  4.   

    flag更新后另外一个线程就可以通过IF()判断语句,虽然这时候没有锁的权限。线程不会自己出来吗?等到头一个线程的Flag语句更新后锁全释放。不就可以继续执行另外一个线程吗?这样理解有没有问题。
      

  5.   

    按楼主的意思,程序改成下面这样(但要去掉其中的 Thread.sleep 代码):
    package a;class Bread {
        String name = "起司";
        int count=0;
        boolean flag = false;
    }
     
    class Maker implements Runnable {
        Bread s ;
        Maker(Bread s) {
            this.s = s;
        }
        public void run() {
            while(true) {
    try{
    Thread.sleep(10);
    }catch(Exception ex){}
    if(!s.flag) {
                synchronized(s) {
                        s.count++;
                        System.out.println("面包师傅生产了"+s.name+"........"+s.count);
                        s.flag = true;
                         
                    }
                }   
            }
        }
    }class Consumer implements Runnable {
        Bread s ;
        Consumer(Bread s) {
            this.s = s;
        }
        public void run() {
            while(true) {
    try{
    Thread.sleep(10);
    }catch(Exception ex){}
    if(s.flag) {
    synchronized(s)  {
    System.out.println("胖子消费了"+s.name+"........"+s.count);
    s.count--;
    s.flag = false;
    }
    }
            }
        }
    }class  Test {
        public static void main(String[] args) {
            Bread s = new Bread();
            Maker a = new Maker(s);
            Consumer b = new Consumer(s);
            Thread t = new Thread(a);
            Thread t2 = new Thread(b);
            t.start();
            t2.start();
        }
    }
    楼主的程序应该不是死锁了,而是其中一个线程进入了死循环,并且没有被打断,导致另一个线程没有执行的机会,可能的情况是:初始时 s.flag = false
    生产者执行 :
    判断 !s.flag = true
    锁 s
    s.count++
    打印
    s.flag = true
    释放锁
    消费者:
    s.flag = true
    锁 s
    打印
    s.count--
    s.flag = false
    程序被打断 // 此时还没有释放锁
    生产者:
    !s.flag = true, 进入if语句块
    尝试取得锁失败,等待消费者
    释放锁
    while 死循环
    进入 if(s.flag) 语句,为 false, 继续 while(true) 语句,进入 if(s.flag) 判断为 false,继续 while(true) ……由于 while 语句没有被打断,导致生产者线程没有机会被执行,因此看起来象是死锁了如果在生产者和消费者的程序中者程序中加上休眠语句,让另外一个线程有机会执行,则不会“死锁”
      

  6.   

    你需要用wait() 和nofiyall()去控制线程之间的互动
      

  7.   


    +2 -1
    使用 wait/notify 的模式控制线程共享资源是最好的办法
    但是,楼主的线程不是被卡住了,而是一个线程进入死循环并且没有被打断,导致另一个线程没有机会执行。我按楼主的意思改了程序,发现“死锁”时,CPU利用率比较高,如果是十年前的单核CPU,估计会达到100%。
      

  8.   


    +1package a;import java.util.*;class Bread {
    boolean stopFlag = false;
    String name = "起司";
    int count = 0;

    public void make(){
    synchronized(this){
    // 库存超过10,则不再生产,等待消费者消耗库存
    while(count >= 10){
    try{
    this.wait();
    }catch(InterruptedException ex){
    }
    }
    count++;
    System.out.println("生产面包,当前库存:" + count);
    this.notifyAll();
    }
    }

    public void consume(){
    synchronized(this){
    // 如果库存为0,则等待生产者生产
    while(count <= 0){
    try{
    this.wait();
    }catch(InterruptedException ex){
    }
    }
    count--;
    System.out.println("消费者消费面包,当前库存:" + count);
    this.notifyAll();
    }
    }
    }class Maker implements Runnable {
    Random rdm = new Random();
        Bread s ;
        Maker(Bread s) {
            this.s = s;
        }
        public void run() {
            while(true) {
    try{
    Thread.sleep(rdm.nextInt(100));
    }catch(Exception ex){
    }
    s.make();
            }
        }
    }class Consumer implements Runnable {
    Random rdm = new Random();
        Bread s ;
        Consumer(Bread s) {
            this.s = s;
        }
        public void run() {
            while(true) {
    try{
    Thread.sleep(rdm.nextInt(100));
    }catch(Exception ex){
    }
    s.consume();
            }
        }
    }class  Test {
        public static void main(String[] args) {
            Bread s = new Bread();
            Maker a = new Maker(s);
            Consumer b = new Consumer(s);
            Thread t = new Thread(a);
            Thread t2 = new Thread(b);
            t.start();
            t2.start();
        }
    }
      

  9.   


    +2 -1
    使用 wait/notify 的模式控制线程共享资源是最好的办法
    但是,楼主的线程不是被卡住了,而是一个线程进入死循环并且没有被打断,导致另一个线程没有机会执行。我按楼主的意思改了程序,发现“死锁”时,CPU利用率比较高,如果是十年前的单核CPU,估计会达到100%。正是因为flag不能被线程正确的赋值,所以才需要用wai() 和nofityall()控制,而且楼主的程序还需要检查count 是否大于0。 wait()和notifyall()跟死锁没关系,而是要控制线程之间的互动。
      

  10.   


    wait/notify 模式与楼主的思路最大的区别在于,wait/notify 是主动放弃线程的执行,等待其它线程唤醒;而楼主的思路是时刻进行询问。
    这就象是
    用楼主的办法:面包店的面包卖完了,胖子不停地问老板,面包做好了没,面包做好了没,面包做好了没……
    而wait/notify 的办法是:面包店的面包卖完了,胖子坐在一边等,当老板的面包做好了,吆喝一声,面包出炉了,大家来买呀
      

  11.   

    这段代码
    class Bread   
    {
        String name = "起司";
        int count=0;
        boolean flag = false;
    }修改成
    class Bread   
    {
        String name = "起司";
        int count=0;
        volatile boolean flag = false;
    }就不会卡死了, 具体原因说来话太长, 就不说了
      

  12.   

    首先,17楼说的正确,按他的修改你的程序就不会卡住了,原因请自行百度volatile,这个牵扯到cpu缓存的问题,说来的确话长,没有一定的计算机原理知识很难理解。再则,7楼说的也正确,虽然17楼的代码解决了你的卡住问题,但不是正道。你通过标志flag可以解决你现有代码的多线程通信问题,但很有局限性。真正灵活的多线程协作还是需要 wait,notify,notifyall这些方法来实现的。当然,新的java版本还有别的解决方案,有兴趣可以继续钻研。
      

  13.   

    看看这个http://www.iamlbk.com/blog/20160109/java-thread-visibility/