线程锁与if结合使用时出现的问题。。这到底是为什么呢?

qq_30550189 2016-09-14 10:26:31
为什么把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)
{


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();
}
}
...全文
653 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
youzi05 2016-09-15
  • 打赏
  • 举报
回复
qq_30550189 2016-09-14
  • 打赏
  • 举报
回复
flag更新后另外一个线程就可以通过IF()判断语句,虽然这时候没有锁的权限。线程不会自己出来吗?等到头一个线程的Flag语句更新后锁全释放。不就可以继续执行另外一个线程吗?这样理解有没有问题。
soton_dolphin 2016-09-14
  • 打赏
  • 举报
回复
你需要用到wait()和notifyall去控制线程用共享的资源。当你的一个线程更新了flag,而另一个线程无法更新的时候,就会卡住了
qq_30550189 2016-09-14
  • 打赏
  • 举报
回复


卡住了。
  • 打赏
  • 举报
回复
引用 3 楼 abcdefghiijklmnopqrs 的回复:
引用 2 楼 qq_30550189 的回复:
这个代码没问题,就是把IF放到synchronized就有问题了。这里出现死锁
我都试过了啊,逻辑也不会产生死锁,
如果你在运行出死锁,截个图,我看看执行的过程
qq_30550189 2016-09-14
  • 打赏
  • 举报
回复
这个代码与上面代码比较,该代码会出现死锁。这是为什么呢。
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();
	}
}
  • 打赏
  • 举报
回复
引用 2 楼 qq_30550189 的回复:
这个代码没问题,就是把IF放到synchronized就有问题了。这里出现死锁
我都试过了啊,逻辑也不会产生死锁,
qq_30550189 2016-09-14
  • 打赏
  • 举报
回复
这个代码没问题,就是把IF放到synchronized就有问题了。这里出现死锁
  • 打赏
  • 举报
回复
没看出有问题,mark
NewMoons 2016-09-14
  • 打赏
  • 举报
回复
首先,17楼说的正确,按他的修改你的程序就不会卡住了,原因请自行百度volatile,这个牵扯到cpu缓存的问题,说来的确话长,没有一定的计算机原理知识很难理解。 再则,7楼说的也正确,虽然17楼的代码解决了你的卡住问题,但不是正道。你通过标志flag可以解决你现有代码的多线程通信问题,但很有局限性。真正灵活的多线程协作还是需要 wait,notify,notifyall这些方法来实现的。当然,新的java版本还有别的解决方案,有兴趣可以继续钻研。
dgqjava 2016-09-14
  • 打赏
  • 举报
回复
这段代码 class Bread { String name = "起司"; int count=0; boolean flag = false; } 修改成 class Bread { String name = "起司"; int count=0; volatile boolean flag = false; } 就不会卡死了, 具体原因说来话太长, 就不说了
小灰狼 2016-09-14
  • 打赏
  • 举报
回复
引用 15 楼 soton_dolphin 的回复:
正是因为flag不能被线程正确的赋值,所以才需要用wai() 和nofityall()控制,而且楼主的程序还需要检查count 是否大于0。 wait()和notifyall()跟死锁没关系,而是要控制线程之间的互动。
wait/notify 模式与楼主的思路最大的区别在于,wait/notify 是主动放弃线程的执行,等待其它线程唤醒;而楼主的思路是时刻进行询问。 这就象是 用楼主的办法:面包店的面包卖完了,胖子不停地问老板,面包做好了没,面包做好了没,面包做好了没…… 而wait/notify 的办法是:面包店的面包卖完了,胖子坐在一边等,当老板的面包做好了,吆喝一声,面包出炉了,大家来买呀
soton_dolphin 2016-09-14
  • 打赏
  • 举报
回复
引用 13 楼 hemowolf 的回复:
[quote=引用 7 楼 soton_dolphin 的回复:] 你需要用到wait()和notifyall去控制线程用共享的资源。当你的一个线程更新了flag,而另一个线程无法更新的时候,就会卡住了
+2 -1 使用 wait/notify 的模式控制线程共享资源是最好的办法 但是,楼主的线程不是被卡住了,而是一个线程进入死循环并且没有被打断,导致另一个线程没有机会执行。我按楼主的意思改了程序,发现“死锁”时,CPU利用率比较高,如果是十年前的单核CPU,估计会达到100%。[/quote] 正是因为flag不能被线程正确的赋值,所以才需要用wai() 和nofityall()控制,而且楼主的程序还需要检查count 是否大于0。 wait()和notifyall()跟死锁没关系,而是要控制线程之间的互动。
小灰狼 2016-09-14
  • 打赏
  • 举报
回复
引用 12 楼 soton_dolphin 的回复:
你需要用wait() 和nofiyall()去控制线程之间的互动
+1
package 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();
    }
}

小灰狼 2016-09-14
  • 打赏
  • 举报
回复
引用 7 楼 soton_dolphin 的回复:
你需要用到wait()和notifyall去控制线程用共享的资源。当你的一个线程更新了flag,而另一个线程无法更新的时候,就会卡住了
+2 -1 使用 wait/notify 的模式控制线程共享资源是最好的办法 但是,楼主的线程不是被卡住了,而是一个线程进入死循环并且没有被打断,导致另一个线程没有机会执行。我按楼主的意思改了程序,发现“死锁”时,CPU利用率比较高,如果是十年前的单核CPU,估计会达到100%。
soton_dolphin 2016-09-14
  • 打赏
  • 举报
回复
你需要用wait() 和nofiyall()去控制线程之间的互动
小灰狼 2016-09-14
  • 打赏
  • 举报
回复
按楼主的意思,程序改成下面这样(但要去掉其中的 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 语句没有被打断,导致生产者线程没有机会被执行,因此看起来象是死锁了 如果在生产者和消费者的程序中者程序中加上休眠语句,让另外一个线程有机会执行,则不会“死锁”
醉蝎目 2016-09-14
  • 打赏
  • 举报
回复
坐等大神帮忙
  • 打赏
  • 举报
回复
引用 8 楼 qq_30550189 的回复:
flag更新后另外一个线程就可以通过IF()判断语句,虽然这时候没有锁的权限。线程不会自己出来吗?等到头一个线程的Flag语句更新后锁全释放。不就可以继续执行另外一个线程吗?这样理解有没有问题。
我也是这么理解的。。。但是你这确实卡住了,坐等大神

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧