The producer-consumption mode usually has two types of threads, namely several producer threads and several consumer threads. The producer thread is responsible for submitting user requests, and the consumer thread is responsible for processing the tasks submitted by the producer. The two communicate with each other through the shared memory buffer.
I. Architecture Pattern diagram:
Class diagram:
Producer: Submit user requests, extract user tasks, and load the tasks into the memory buffer;
Consumer: extract and process tasks in the memory buffer;
Memory Buffer: cache the tasks or data submitted by the producer for consumers;
Task: Data Structure submitted by the producer to the memory buffer;
Main: Use the producer and consumer client.
2. The Code implements a Parallel Computing Based on the producer-consumer model to calculate the integer square:
(1) Producer thread:
<Span style = "font-size: 18px;"> package producerconsumer; import Java. util. random; import Java. util. concurrent. blockingqueue; import Java. util. concurrent. timeunit; import Java. util. concurrent. atomic. atomicinteger; public class producer implements runnable {// The member variable modified by volatile forces the value of this member variable to be re-read from the shared memory each time it is accessed by a thread. // When the member variables change, the thread is forced to write the change value back to the shared memory. // At any time, two different threads always see the same value of a member variable. Private volatile Boolean isrunning = true; // memory buffer private blockingqueue <pcdata> queue; // total number of Private Static atomicinteger COUNT = new atomicinteger (); private Static final int sleeptime = 1000; Public producer (blockingqueue <pcdata> Queue) {This. queue = queue;} @ overridepublic void run () {pcdata DATA = NULL; random r = new random (); system. out. println ("START producer id =" + thread. currentthread (). GETID ()); Try {While (isrunning) {thread. sleep (R. nextint (sleeptime); // construct the task data = new pcdata (count. incrementandget (); system. out. println ("data is put into queue"); // submit data to the buffer if (! Queue. offer (data, 2, timeunit. seconds) {system. out. println ("faile to put data:" + Data) ;}} catch (interruptedexception e) {e. printstacktrace (); thread. currentthread (). interrupt () ;}} public void stop () {isrunning = false ;}}</span>
(2) Consumer consumer thread:
<Span style = "font-size: 18px;"> package producerconsumer; import Java. text. messageformat; import Java. util. random; import Java. util. concurrent. blockingqueue; public class Consumer implements runnable {// buffer private blockingqueue <pcdata> queue; Private Static final int sleeptime = 1000; public consumer (blockingqueue <pcdata> Queue) {This. queue = queue;} @ overridepublic void run () {system. out. println ("START consu Mer id = "+ thread. currentthread (). GETID (); random r = new random (); try {// extract task while (true) {pcdata DATA = queue. take (); If (null! = Data) {// calculates the square int Re = data. getdata () * data. getdata (); system. out. println (messageformat. format ("{0} * {1} = {2}", Data. getdata (), Data. getdata (), Re); thread. sleep (R. nextint (sleeptime) ;}} catch (interruptedexception e) {e. printstacktrace (); thread. currentthread (). interrupt () ;}}</span>
(3) pcdata shared data model:
<span style="font-size:18px;">package ProducerConsumer;public final class PCData {private final int intData;public PCData(int d) {intData=d;}public PCData(String d) {intData=Integer.valueOf(d);}public int getData(){return intData;}@Overridepublic String toString(){return "data:"+ intData ;}}</span>
(4) main function:
<Span style = "font-size: 18px;"> package producerconsumer; import Java. util. concurrent. blockingqueue; import Java. util. concurrent. executor; import Java. util. concurrent. executorservice; import Java. util. concurrent. executors; import Java. util. concurrent. linkedblockingdeque; public class main {/*** @ Param ARGs */public static void main (string [] ARGs) throws interruptedexception {// create a buffer blockingqueue <pcdata> queue = new linkedblockingdeque <pcdata> (10); // create a producer producer1 = new producer (Queue ); producer producer2 = new producer (Queue); Producer producer3 = new producer (Queue); // create consumer consumer1 = new consumer (Queue); consumer consumer2 = new consumer (Queue ); consumer consumer3 = new consumer (Queue); // create a thread pool executorservice service = executors. newcachedthreadpool (); // run the service.execute(producer1);service.execute(producer2;;service.exe cute (producer3); // consume cute (consumer3); thread. sleep (10*1000); // stop the producer producer1.stop (); producer2.stop (); producer3.stop (); thread. sleep (3000); service. shutdown () ;}</span>
3. Note:
Volatile Keyword: when a member variable modified by volatile is accessed by a thread, the value of the member variable is forcibly re-read from the shared memory. In addition, when the member variables change, the thread is forced to write the change value back to the shared memory. In this way, two different threads always see the same value of a member variable at any time.
The core component of the production-consumption mode is the shared memory buffer, which serves as a communication bridge between the two and serves as a decoupling function to optimize the overall structure of the system.
Because of the existence of the buffer zone, producers and consumers can use the buffer zone to alleviate the high speed in a certain part of time to ensure normal system operation, this relieves the impact of performance bottlenecks on system performance to a certain extent.
Concurrency mode (3) -- producer-consumption mode