Producer-consumer model, producer-consumer model
The producer-consumer model is a classic multi-threaded design model that provides a good solution for multi-threaded collaboration. In producer-consumer mode, there are two types of threads: several producer threads and several consumer threads. The producer submits user requests, and the consumer processes the tasks submitted by the producer. Producer and consumer data communication through the shared memory buffer.
The basic structure of the producer-consumer model is as follows:
It can be seen that the producer and consumer communicate through the shared memory buffer, and there is no direct communication between them, thus reducing the coupling between them. The producer does not need to wait until the consumer exists, consumers do not need to know the existence of producers. The main function of the memory buffer is to share data among multiple threads. In addition, the buffer can alleviate performance differences between producers and consumers.
- Producer-consumer model implementation
The following describes the advantages of the producer-consumer mode:
Producer code:
1 public class Producer implements Runnable {2 3 private volatile boolean isRunnig = true; 4 5 private BlockingQueue <PCData> queue; // Buffer queue 6 7 private static AtomicInteger count = new AtomicInteger (); 8 9 private static final int SLEEPTIME = 1000; 10 11 12 public Producer (BlockingQueue <PCData> queue) {13 this. queue = queue; 14} 15 16 17 @ Override18 public void run () {19 PCData pcData = null; 20 Random R = new Random (); 21 22 System. out. println ("start producer id:" + Thread. currentThread (). getId (); 23 24 try {25 while (true) {26 Thread. sleep (r. nextInt (SLEEPTIME); 27 pcData = new PCData (count. incrementAndGet (); 28 System. out. println (pcData + "is put into queue"); 29 if (! Queue. offer (pcData, 2, TimeUnit. SECONDS) {30 System. err. println ("fail to put data:" + pcData); 31} 32} 33} catch (Exception e) {34 // TODO: handle exception35 e. printStackTrace (); 36 Thread. currentThread (). interrupt (); 37} 38 39} 40 41 public void stop () {42 isRunnig = false; 43} 44 45 46}
Consumer Code:
1 public class Consumer implements Runnable {2 3 private BlockingQueue <PCData> queue; // Buffer queue 4 5 private static final int SLEEPTIME = 1000; 6 7 8 9 public Consumer (BlockingQueue <PCData> queue) {10 this. queue = queue; 11} 12 13 14 15 @ Override16 public void run () {17 System. out. println ("start constomer id:" + Thread. currentThread (). getId (); 18 Random r = new Random (); 19 try {20 while (true) {21 PCData data = queue. take (); 22 int re = data. getIntData () * data. getIntData (); 23 System. out. println (MessageFormat. format ("{0} * {1} = {2}", data. getIntData (), data. getIntData (), re); 24 25 Thread. sleep (r. nextInt (SLEEPTIME); 26} 27} catch (Exception e) {28 // TODO: handle exception29 e. printStackTrace (); 30 Thread. currentThread (). interrupt (); 31} 32 33} 34 35}
Shared data models between consumers and producers:
1 public final class PCData { 2 private final int intData; 3 4 public PCData(int intData) { 5 this.intData = intData; 6 } 7 8 public PCData(String strData){ 9 this.intData = Integer.valueOf(strData);10 }11 12 public synchronized int getIntData() {13 return intData;14 }15 16 @Override17 public String toString() {18 return "data:" + intData;19 }20 21 22 23 }
In the client, start three consumers and three producers and let them run in collaboration:
1 public class Client { 2 public static void main(String[] args) throws InterruptedException { 3 BlockingQueue<PCData> queue = new LinkedBlockingQueue<PCData>(10); 4 5 Producer p1 = new Producer(queue); 6 Producer p2 = new Producer(queue); 7 Producer p3 = new Producer(queue); 8 9 Consumer c1 = new Consumer(queue);10 Consumer c2 = new Consumer(queue);11 Consumer c3 = new Consumer(queue);12 13 ExecutorService exe = Executors.newCachedThreadPool();14 exe.execute(p1);15 exe.execute(p2);16 exe.execute(p3);17 18 exe.execute(c1);19 exe.execute(c2);20 exe.execute(c3);21 22 Thread.sleep(10*1000);23 24 p1.stop();25 p2.stop();26 p3.stop();27 28 Thread.sleep(3000);29 exe.shutdown();30 }31 }
Advantage: the producer-consumer mode can well decouple producer threads and consumer threads to optimize the overall structure of the system. At the same time, due to the existence of the buffer, there are certain performance differences between the operation producer and consumer, thus alleviating the impact of performance bottleneck on the system performance to a certain extent.