JAVA多线程之生产者消费者问题

1.问题概述:

开辟一条线程代表生产者,开辟另一条线程代表消费者。生产者和消费者轮流生产和消费。生产和消费的数量使用随机数代替即可。生产者每次生产的产品数量+剩余的产品数量不能大于1000。
用到的方法:
(1)run()
定义线程中执行的内容。
(2)start()
表示开启线程,把当前的线程run();隔离成一个单独的任务。
(3)wait()
使线程进入等待状态,并且会释放被同步对象的锁。
(4) notify()
唤醒处于等待状态的线程。

2.代码实现

package thread;
	// 开辟一条线程代表生产者,开辟另一条线程代表消费者。
	// 生产者生产产品后,消费者进行消费。生产者和消费者轮流生产和消费。
	// 生产和消费的数量使用随机数代替即可。生产者每次生产的产品数量+剩余的产品数量不能大于1000.
public class Demo {
	public static void main(String[] args) {
		Product p = new Product();
		// 开辟新的线程去生产
		new Thread(new Producter(p)).start();
		// 开辟新的线程去消费
		new Thread(new Consumer(p)).start();
	}
}

// 消费者
class Consumer implements Runnable {
	private Product p;

	public Consumer(Product p) {
		this.p = p;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (p) {
				if (p.flag) {
					try {
						p.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				// 计算本次消费的数量
				int count = (int) (Math.random() * (p.getCount() + 1));
				// 提供剩余数量
				p.setCount(p.getCount() - count);

				System.out.println("本次消费的数量是" + count + ",剩余数量为" + p.getCount());

				// 修改flag
				p.flag = true;
				// 唤醒线程
				p.notify();
			}
		}
	}

}

// 生产者
class Producter implements Runnable {
	private Product p;

	public Producter(Product p) {
		this.p = p;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (p) {
				// 如果flag=false,表示需要消费,生产进程进入阻塞队列
				if (!p.flag) {
					try {
						p.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				// 计算能够生产的最大数量
				int max = 1000 - p.getCount();
				// 实际生产的数量。Math的random()方法提供一个[0,1)之间的随机数。
				// +1和强转为int类型的操作弥补了random方法不能提供随机数为1的不足。
				int count = (int) (Math.random() * (max + 1));
				// 可消费的商品量=此次产生的商品量加余下的商品
				p.setCount(count + p.getCount());

				System.out.println("本次实际生产的数量为" + count + ",本次提供的数量为" + p.getCount());

				// 切换flag值
				p.flag = false;
				// 唤醒
				p.notify();
			}

		}
	}

}

// 产品
class Product {
	// 代表商品数量
	private int count;
	// 如果flag是true,那么生产
	// 如果flag是false,那么就消费
	boolean flag = true;

	// 获取商品数量
	public int getCount() {
		return count;
	}

	// 记录商品数量
	public void setCount(int count) {
		this.count = count;
	}

}

3.运行结果

输出结果如下:

&:因为数值都是随机获取的,所以答案会有差异。只要套的起来就行了。

4.分析

创建两个子线程后,产生两种情况:

1.生产者线程先执行,程序运行步骤如下:
(1)执行同步块,获得资源p的锁。flag=true,跳过wait方法,生产产品,统计总量,输出,flag=false,执行notify方法,唤醒在阻塞队列中的线程(此时还没有在等待的线程)。回头执行while语句,true,执行同步块,获得资源p的锁,flag=false,执行wait方法,生产者线程进入阻塞状态,并立即释放CPU的控制权,释放资源p的锁。
(2)消费者线程执行run方法,执行同步块,获得资源p的锁。flag=false,,跳过wait方法。消费产品,统计总量,输出,flag=true,执行notify方法,唤醒在等待的生产者线程,释放资源p的锁。回头再进入同步块,获得资源p的锁,flag=true,执行wait方法,消费者线程进入阻塞状态,并立即释放CPU的控制权,释放资源p的锁。
(3)随后生产者线程获得资源p的锁,从上次阻塞的地方继续开始执行。生产产品,统计总量,输出,flag=false,执行notify方法,唤醒在等待的消费者线程。然后再生产者进程阻塞,消费者进程执行,如此一直反复下去,乐此不疲。

2.消费者线程先执行,程序运行步骤如下:
(1)run方法,执行同步块,获得资源p的锁,flag=true,消费者进程阻塞。生产者线程执行,run方法,执行同步块,获得资源p的锁。flag=true,跳过wait方法,生产产品,统计总量,输出,flag=false,执行notify方法,唤醒在阻塞队列中的消费者线程。
(2)回头执行while语句,true,执行同步块,获得资源p的锁,flag=false,执行wait方法,生产者线程进入阻塞状态,并立即释放CPU的控制权,释放资源p的锁。
(3)接情况1的步骤2.


以上内容为自己学习总结,仅供参考,若有不足
欢迎大家与我交流,一起学习,一起进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值