Java multithreading series - the problem of production and consumers


640?wxfrom=5&wx_lazy=1

Source: Blog Park | Author: If the sky didn't die


Overview

In this chapter, the "producer/consumer problem" is discussed. The content involved includes:
1. Producer/Consumer Model
2. Producer/Consumer Implementation

1. Producer/Consumer Model

The production/consumer problem is a very typical multithreading problem, and the objects involved include "producer", "consumer", "repository" and "product". The relationship between them is as follows:
(01) Producers only produce when the warehouse is not full, and stop production when the warehouse is full.
(02) Consumers can only consume when there are products in the warehouse, and wait when the warehouse is empty.
(03) When consumers find that there is no product available in the warehouse, they will notify the producer to produce.
(04) When producers produce consumable products, they should notify waiting consumers to consume them.

2. Producer/Consumer Implementation

The model is implemented by the wait()/notify() method below ( after learning the thread pool related content, the production/consumer model will be implemented in other ways ). The source code is as follows:

1 // Demo1.java
 2 // 仓库
 3 class Depot {
 4     private int capacity;    // 仓库的容量
 5     private int size;        // 仓库的实际数量
 6
 7     public Depot(int capacity) {
 8         this.capacity = capacity;
 9         this.size = 0;
10     }
11
12     public synchronized void produce(int val) {
13         try {
14              // left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
15             int left = val;
16             while (left > 0) {
17                 // 库存已满时,等待“消费者”消费产品。
18                 while (size >= capacity)
19                     wait();
20                 // 获取“实际生产的数量”(即库存中新增的数量)
21                 // 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
22                 // 否则“实际增量”=“想要生产的数量”
23                 int inc = (size+left)>capacity ? (capacity-size) : left;
24                 size += inc;
25                 left -= inc;
26                 System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
27                         Thread.currentThread().getName(), val, left, inc, size);
28                 // 通知“消费者”可以消费了。
29                 notifyAll();
30             }
31         } catch (InterruptedException e) {
32         }
33     }
34
35     public synchronized void consume(int val) {
36         try {
37             // left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
38             int left = val;
39             while (left > 0) {
40                 // 库存为0时,等待“生产者”生产产品。
41                 while (size <= 0)
42                     wait();
43                 // 获取“实际消费的数量”(即库存中实际减少的数量)
44                 // 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
45                 // 否则,“实际消费量”=“客户要消费的数量”。
46                 int dec = (size<left) ? size : left;
47                 size -= dec;
48                 left -= dec;
49                 System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
50                         Thread.currentThread().getName(), val, left, dec, size);
51                 notifyAll();
52             }
53         } catch (InterruptedException e) {
54         }
55     }
56
57     public String toString() {
58         return "capacity:"+capacity+", actual size:"+size;
59     }
60 }
61
62 // 生产者
63 class Producer {
64     private Depot depot;
65    
66     public Producer(Depot depot) {
67         this.depot = depot;
68     }
69
70     // 消费产品:新建一个线程向仓库中生产产品。
71     public void produce(final int val) {
72         new Thread() {
73             public void run() {
74                 depot.produce(val);
75             }
76         }.start();
77     }
78 }
79
80 // 消费者
81 class Customer {
82     private Depot depot;
83    
84     public Customer(Depot depot) {
85         this.depot = depot;
86     }
87
88     // 消费产品:新建一个线程从仓库中消费产品。
89     public void consume(final int val) {
90         new Thread() {
91             public void run() {
92                 depot.consume(val);
93             }
94         }.start();
95     }
96 }
97
98 public class Demo1 {  
99     public static void main(String[] args) {  
100         Depot mDepot = new Depot(100);
101         Producer mPro = new Producer(mDepot);
102         Customer mCus = new Customer(mDepot);
103
104         mPro.produce(60);
105         mPro.produce(120);
106         mCus.consume(90);
107         mCus.consume(150);
108         mPro.produce(110);
109     }
110 }

Description :
(01) Producer is a "producer" class, which is associated with a "depot". When the "producer"'s produce() method is called, it creates a new thread and produces the product in the "repository".
(02) Customer is a "consumer" class, which is associated with a "depot". When the "consumer"'s consume() method is called, it creates a new thread and consumes the products in the "repository".
(03) Depot is a "warehouse" class, and the "warehouse capacity (capacity)" and "the current number of products in the warehouse (size)" are recorded in the warehouse.
        The production method produce() and the consumption method consume() of the "Warehouse" class are both synchronized methods. Entering the synchronized method body means that this thread has acquired the synchronization lock of the "Warehouse" object. This means that at the same time, only one of the producer and consumer threads can be running. Through synchronization locks, "brutal" mutually exclusive access is achieved.
       For the production method produce() : when the warehouse is full, the producer thread waits and waits for the consumer to consume the product before the production thread can produce; after the producer thread finishes producing the product, it will wake up the synchronization lock through notifyAll(). All threads, including "consumer threads", which we call "notifying consumers to consume".
      For the consumption method consume() : when the warehouse is empty, the consumer thread waits and needs to wait for the producer to produce the product before the consumer thread can consume it; after the consumer thread finishes consuming the product, it will wake up the synchronization lock through notifyAll(). All threads on , including the "producer thread", which is what we call "notifying the producer to produce".

(One time) running result :

Thread-0 produce( 60) --> left=  0, inc= 60, size= 60
Thread-4 produce(110) --> left= 70, inc= 40, size=100
Thread-2 consume( 90) <-- left=  0, dec= 90, size= 10
Thread-3 consume(150) <-- left=140, dec= 10, size=  0
Thread-1 produce(120) --> left= 20, inc=100, size=100
Thread-3 consume(150) <-- left= 40, dec=100, size=  0
Thread-4 produce(110) --> left=  0, inc= 70, size= 70
Thread-3 consume(150) <-- left=  0, dec= 40, size= 30
Thread-1 produce(120) --> left=  0, inc= 20, size= 50
Recommended reading

The 20th Dachang Harvest Road

Initialization order of classes in Java

640?

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325602025&siteId=291194637