1、仓库
1 package com.cn.donleo.thread.house;
2
3 /**
4 * @author liangd
5 * date 2020-11-02 10:36
6 * code 仓库
7 */
8 public class StoreHouse {
9 /**
10 * 仓库容纳数量
11 */
12 public static int count = 10;
13 /**
14 * 判断仓库是否有东西
15 */
16 public static Boolean isNull =false;
17 public static final Object OBJECT = new Object();
18 }
2、生产者
1 package com.cn.donleo.thread.house;
2
3 /**
4 * @author liangd
5 * date 2020-11-02 10:40
6 * code
7 */
8 public class Productor extends Thread {
9 /**
10 * 对于生产者来说,我们需要以下几个步骤:
11 * 判断生产者是否还可以生产,因为规定一天只生产10个,可以则继续,不能则返回
12 * 第一:判断仓库里面是否有还有物品
13 * 第二:如果有,则线程等待,即等待消费者来拿
14 * 第三:如果没有,则生产物品,并提示仓库里面有东西,并呼叫消费者
15 * 生产者的run方法,一直向仓库添加元素
16 */
17 @Override
18 public void run() {
19 while (true) {
20 //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西,
21 //所以不能用new WareHouse(),来创建对象
22 synchronized (StoreHouse.OBJECT) {
23 if (StoreHouse.count == 0) {
24 break;
25 } else {
26 if (!StoreHouse.isNull) {
27 System.out.println(getName() + "生产者生产产品");
28 StoreHouse.isNull = true;
29 /*
30 一、notify和notifyAll的区别
31 主要区别:notify和notifyAll之间的关键区别在于notify()只会唤醒一个线程,
32 而notifyAll方法将唤醒所有线程。
33
34 二、何时在Java中使用notify和notifyAll?
35 1、如果所有线程都在等待相同的条件,并且一次只有一个线程可以从条件变为true,
36 则可以使用notify over notifyAll。
37 2、在这种情况下,notify是优于notifyAll 因为唤醒所有这些因为我们知道只有一个线程会受益
38 而所有其他线程将再次等待,所以调用notifyAll方法只是浪费CPU。
39 3、虽然这看起来很合理,但仍有一个警告,即无意中的接收者吞下了关键通知。
40 通过使用notifyAll,我们确保所有收件人都会收到通知
41
42 */
43 StoreHouse.OBJECT.notifyAll();
44 } else {
45 try {
46 /*
47 一、notify、 notifyAll、wait属于Object里面的方法
48 二、sleep和wait有什么区别
49 1、Sleep是属于Thread类的静态方法,wait属于Object的方法。
50 2、最主要是sleep方法没有释放锁,而是放弃CPU的调度。而wait方法释放了锁,
51 使得其他线程可以进入同步控制块或者方法。
52 3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,
53 而sleep可以在任何地方使用,synchronized(x){x.notify()//或者wait()}
54 4、sleep必须捕获异常,wait也需要捕获异常,notify和notifyAll不需要捕获异常
55 5、使用wait,notify可以达到线程之间的通信目的
56 */
57 /*
58 1.使用sleep方法,在毫秒值结束后,线程睡醒进入到Runnable/blocked状态
59 2.使用wait方法,wait方法如果在毫秒值结束后,还没有被notify唤醒,就会自动醒来,
60 线程睡醒进入到Runnable/blocked状态
61 */
62 StoreHouse.OBJECT.wait();
63 // StoreHouse.OBJECT.wait(500);
64 } catch (InterruptedException e) {
65 e.printStackTrace();
66 }
67 }
68 }
69 }
70 }
71 }
72 }
3、消费者
1 package com.cn.donleo.thread.house;
2
3 /**
4 * @author liangd
5 * date 2020-11-02 10:40
6 * code
7 */
8 public class Consumer extends Thread {
9 /**
10 * 1.while(true)
11 * 2.synchronized ()
12 * 3.判断生产者是否已经停止生产了,如果已经停止了,就跳出,如果没有,则可以继续去仓库拿
13 * 4.判断仓库是否有物品,如果有,则直接拿。拿了就需要讲次数减一,然后呼叫生产者生产
14 * 5.如果没有,则等待生产者生产
15 */
16 @Override
17 public void run() {
18 while (true) {
19 //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西,
20 //所以不能用new WareHouse(),来创建对象
21 synchronized (StoreHouse.OBJECT) {
22 try {
23 //休眠0.5s
24 Thread.sleep(500);
25 } catch (InterruptedException e) {
26 e.printStackTrace();
27 }
28 if (StoreHouse.count == 0) {
29 break;
30 } else {
31 if (StoreHouse.isNull) {
32 System.out.println(getName() + "消费者可以拿产品了");
33 StoreHouse.isNull = false;
34 StoreHouse.OBJECT.notifyAll();
35 StoreHouse.count--;
36 } else {
37 try {
38 StoreHouse.OBJECT.wait();
39 } catch (InterruptedException e) {
40 e.printStackTrace();
41 }
42 }
43 }
44 }
45 }
46 }
47 }
4、测试类
1 package com.cn.donleo.thread.house;
2
3 /**
4 * @author liangd
5 * date 2020-11-02 10:56
6 * code 生产者消费者测试类
7 */
8 public class TestProductorCunsumer {
9 public static void main(String[] args){
10 //线程1
11 Productor productor = new Productor();
12 productor.setName("生产者");
13 //线程2
14 Consumer consumer1 = new Consumer();
15 consumer1.setName("A消费者");
16 //线程3
17 Consumer consumer2 = new Consumer();
18 consumer2.setName("B消费者");
19 productor.start();
20 consumer1.start();
21 consumer2.start();
22 }
23 }