多线程编程-“对资源的使用条件做判断时”使用while和if的区别

在多线程的情况下,对资源的使用条件做判断时,我们需要使用while而不是if

例子:

现在有一个资源类“蛋糕”,两个操作,“买蛋糕”和“做蛋糕”,这里有两种线程,一百个“蛋糕店线程“,一百个“顾客线程”。当蛋糕数量为0时,“蛋糕店线程“执行“做蛋糕操作”,当蛋糕数量为1时,顾客执行“买蛋糕操作”。

代码:
/**
 * 
 * @ClassName: Cake
 * @Description: 蛋糕资源类
 * @author: fuling
 * @date: 2020年9月9日 下午2:04:58
 */
class Cake{
	public int count;//蛋糕的数量
	
	
	/**
	 * 
	 * @Title: makeCake
	 * @Description: 做蛋糕操作(synchronized)
	 * @return: void
	 * @throws InterruptedException 
	 */
	public synchronized void makeCake() throws InterruptedException {
		//如果当前蛋糕数量大于0,则等待
		if(count > 0) {
			wait();
		}

		System.out.println(Thread.currentThread().getName() + ":正在做蛋糕。。。目前蛋糕数量:" + count);
		count++;
		notifyAll();
	} 
	
	/**
	 * 
	 * @Title: buyCake
	 * @Description: 买蛋糕操作(synchronized)
	 * @return: void
	 * @throws InterruptedException 
	 */
	public synchronized void buyCake() throws InterruptedException {
		//如果当前蛋糕数量为0,则等待
		if(count == 0) {
			wait();
		}
	
		System.out.println(Thread.currentThread().getName() + ":正在买蛋糕。。。目前蛋糕数量:" + count);
		count--;
		
	
		notifyAll();
	}
	
	
}

/**
 * 
 * @ClassName: LockDemo
 * @Description: 启动类
 * @author: fuling
 * @date: 2020年9月9日 下午2:03:21
 */
public class LockDemo {
	public static void main(String[] args) {
		
		//蛋糕资源类
		Cake cake = new Cake();
		
		//100个蛋糕店线程
		for(int i = 0; i < 100; i++) {
			new Thread(()->{
				try {
					cake.makeCake();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}, "蛋糕店线程" + (i + 1)).start();
		}
		
		//100个顾客线程
		for(int i = 0; i < 100; i++) {
			new Thread(()->{
				try {
					cake.buyCake();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}, "顾客线程" + (i + 1)).start();
		}
		
		
	}
}

我们的想法是,“蛋糕店线程”做一个蛋糕,“顾客线程“买一个蛋糕这样交替进行,我们需要实现蛋糕数量按0,1,0,1变化

想实现的结果:

蛋糕店线程81:正在做蛋糕。。。目前蛋糕数量:0
顾客线程60:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程67:正在做蛋糕。。。目前蛋糕数量:0
顾客线程58:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程68:正在做蛋糕。。。目前蛋糕数量:0
顾客线程61:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程71:正在做蛋糕。。。目前蛋糕数量:0
顾客线程64:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程72:正在做蛋糕。。。目前蛋糕数量:0
顾客线程66:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程70:正在做蛋糕。。。目前蛋糕数量:0
顾客线程72:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程73:正在做蛋糕。。。目前蛋糕数量:0
顾客线程79:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程74:正在做蛋糕。。。目前蛋糕数量:0
顾客线程87:正在买蛋糕。。。目前蛋糕数量:1

执行结果:

蛋糕店线程1:正在做蛋糕。。。目前蛋糕数量:0
顾客线程1:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程100:正在做蛋糕。。。目前蛋糕数量:0
蛋糕店线程99:正在做蛋糕。。。目前蛋糕数量:1
蛋糕店线程98:正在做蛋糕。。。目前蛋糕数量:2
蛋糕店线程97:正在做蛋糕。。。目前蛋糕数量:3
蛋糕店线程94:正在做蛋糕。。。目前蛋糕数量:4
蛋糕店线程96:正在做蛋糕。。。目前蛋糕数量:5
蛋糕店线程95:正在做蛋糕。。。目前蛋糕数量:6
蛋糕店线程93:正在做蛋糕。。。目前蛋糕数量:7
蛋糕店线程92:正在做蛋糕。。。目前蛋糕数量:8
蛋糕店线程91:正在做蛋糕。。。目前蛋糕数量:9
蛋糕店线程88:正在做蛋糕。。。目前蛋糕数量:10
蛋糕店线程90:正在做蛋糕。。。目前蛋糕数量:11

问题分析:

“蛋糕店线程”执行“做蛋糕”操作后notify唤醒的可能是另一个“蛋糕店线程”,使得”蛋糕“数量出现大于1的情况!其根源在于两点:1.notify是随机唤醒线程!2.线程被唤醒之后没有再次检查蛋糕的数量。假设有这样一个场景:”蛋糕店线程1“首先抢夺到锁,但此时蛋糕数量为1,所以”蛋糕店线程1“等待,蛋糕店线程2“,蛋糕店线程3“亦如此,直到“顾客线程”抢夺到锁,执行“买蛋糕操作”后蛋糕数量为0,随机唤醒一个线程,假设唤醒的是”蛋糕店线程1“,则”蛋糕店线程1“执行”做蛋糕操作“后,蛋糕数量为1,然后随机唤醒一个线程,注意,这里接下来有可能唤醒的是另一个”蛋糕店线程“,比如“蛋糕店线程2”,而不是“顾客线程”,又由于if之后没有继续判断当前蛋糕数量,“蛋糕店线程2”被唤醒后直接执行后续”做蛋糕操作“,使得蛋糕数量为2!

解决方法:

使用while代替if,每次线程被唤醒之后都可以再次检查蛋糕数量

代码:
/**
 * 
 * @ClassName: Cake
 * @Description: 蛋糕资源类
 * @author: fuling
 * @date: 2020年9月9日 下午2:04:58
 */
class Cake{
	public int count;//蛋糕的数量
	
	
	/**
	 * 
	 * @Title: makeCake
	 * @Description: 做蛋糕操作(synchronized)
	 * @return: void
	 * @throws InterruptedException 
	 */
	public synchronized void makeCake() throws InterruptedException {
		//如果当前蛋糕数量大于0,则等待
		while(count > 0) {
			wait();
		}
		System.out.println(Thread.currentThread().getName() + ":正在做蛋糕。。。目前蛋糕数量:" + count);
		count++;
		notifyAll();
	} 
	
	/**
	 * 
	 * @Title: buyCake
	 * @Description: 买蛋糕操作(synchronized)
	 * @return: void
	 * @throws InterruptedException 
	 */
	public synchronized void buyCake() throws InterruptedException {
		//如果当前蛋糕数量为0,则等待

		while(count == 0) {
			wait();
		}
		System.out.println(Thread.currentThread().getName() + ":正在买蛋糕。。。目前蛋糕数量:" + count);
		count--;
		
	
		notifyAll();
	}
	
	
}
执行结果:

蛋糕店线程1:正在做蛋糕。。。目前蛋糕数量:0
顾客线程1:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程99:正在做蛋糕。。。目前蛋糕数量:0
顾客线程5:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程33:正在做蛋糕。。。目前蛋糕数量:0
顾客线程6:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程3:正在做蛋糕。。。目前蛋糕数量:0
顾客线程8:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程30:正在做蛋糕。。。目前蛋糕数量:0
顾客线程7:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程34:正在做蛋糕。。。目前蛋糕数量:0
顾客线程11:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程64:正在做蛋糕。。。目前蛋糕数量:0
顾客线程3:正在买蛋糕。。。目前蛋糕数量:1
蛋糕店线程100:正在做蛋糕。。。目前蛋糕数量:0
顾客线程12:正在买蛋糕。。。目前蛋糕数量:1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值