Preface: Recently in learning Java Multi-threading, see Importnew Online has a netizen translation of an article "block queue to achieve producer consumer model". In this article, the blocking queue in Java's concurrent package is used. After reading, implement the blocking queue by itself.
(i) Preparation
In multi-threading, producer-consumer issues are a classic multithreaded synchronization issue. In short, there are two types of threads (which can also be understood here)-producers and consumers, who share a fixed-size buffer (such as a queue). Producers are responsible for generating new data, and consumers are responsible for extracting the buffer data. Please refer to Producer-consumer problem for details.
(ii) Design overview
detailed code can go to my Github repository Download (Master branch For detailed code, output all necessary information; Simplification branch for simplified code).
The project code is divided into four classes: the consumer class is the consumer thread, the producer class is the producer thread, the Producerconsumer tests the startup class, and the Producerconsumerqueue class is the blocking queue.
In multi-threading, the producer keeps putting new data into the queue, and when the queue is full, the producer is blocked until the consumer pulls some of the data out of the queue and wakes the producer; Consumers are constantly pulling data out of the queue, and when the queue is empty, consumers will be blocked until the producer puts new data in again and wakes up the consumer. In the Java concurrent package, a series of blocking queues are provided to help us do this. This work is also precisely the key to the problem of producer consumers. Here, I will implement the blocking queue on my own: Producerconsumerqueue;
(iii) Detailed implementation
(1) Producerconsumerqueue class
1 Public Final classProducerconsumerqueue<e> {2 //declaring a re-entry lock3 Private FinalLock lock =NewReentrantlock ();4 Private FinalCondition Notempty =lock.newcondition ();5 Private FinalCondition Notfull =lock.newcondition ();6 //Cache Size7 Private Final intcapacity;8 //cache queue for storing data9 PrivateQueue<e>queue;Ten One PublicProducerconsumerqueue (intcapacity) { A This. Capacity =capacity; - This. Queue =NewLinkedlist<e>(); - } the - //put the E into the the queue - Public voidPut (e e)throwsinterruptedexception { - Lock.lock (); + - Try { + while(queue.size () = = This. capacity) A This. notfull.await (); at Queue.offer (e); - This. Notempty.signalall (); -}finally { - Lock.unlock (); - } - } in - //get e from the queue. to PublicE Take ()throwsinterruptedexception { + Lock.lock (); - the Try { * while(queue.size () = = 0) $ This. notempty.await ();Panax Notoginseng This. Notfull.signalall (); - returnQueue.poll (); the}finally { + Lock.unlock (); A } the } +}
The queue provides the put () and take () methods, which are used by the producer to put data, which is used by consumers to extract data.
In the Put method, you first get the lock. Then detects if the queue is full, if it is, blocks the producer thread, and releases the lock; When the lock is acquired again, the while statement is used here, allowing the thread to check again if the queue is full, if it is not full, to put the data into the cache, and to wake up the consumer thread that might be blocking. Use while to prevent other producer threads from waking up and successfully putting new data into the queue, then blocking, and then putting the thread back in again, causing a possible cache overflow.
In the Take method, the lock is also acquired first. Detects if the queue is empty, if it is, blocks the consumer thread, releases the lock, and when it wakes up and obtains the lock again, checks to see if the queue is still empty, if not empty, and then extracts the cached data. While also to prevent other consumers from fetching data on an empty queue.
(2) Consumer class
1 Public classConsumerImplementsRunnable {2 Private Finalproducerconsumerqueue Sharedqueue;3 4 PublicConsumer (Producerconsumerqueue sharedqueue) {5 This. Sharedqueue =Sharedqueue;6 }7 8 @Override9 Public voidrun () {Ten while(true) { One Try { A synchronized( This){ -System.out.println ("\tconsumer:" +Sharedqueue.take ()); - } the}Catch(Interruptedexception ex) { -System.out.println (Thread.CurrentThread (). GetName () + "throw a interrupexception."); - //Do something. - } + } - } +}
The consumer thread continues to fetch data from the queue.
(3) Producer class
1 Public classProducerImplementsRunnable {2 Private Finalproducerconsumerqueue Sharedqueue;3 4 PublicProducer (Producerconsumerqueue sharedqueue) {5 This. Sharedqueue =Sharedqueue;6 }7 8 @Override9 Public voidrun () {Ten for(inti = 0; I < 20; i++) { One Try { A synchronized( This){ -System.out.println ("Producer:" +i); - sharedqueue.put (i); the } -}Catch(Interruptedexception ex) { -System.out.println (Thread.CurrentThread (). GetName () + "throw a interrupexception."); - //Do something. + } - } + } A}
The producer thread generates the data and puts it into the queue.
(4) Producerconsumer test class
Public classProducerconsumer { Public Static voidMain (string[] args) {producerconsumerqueue sharedqueue=NewProducerconsumerqueue (4); Thread Prodthread=NewThread (NewProducer (sharedqueue)); Thread ConsThread1=NewThread (NewConsumer (sharedqueue)); Thread consThread2=NewThread (NewConsumer (sharedqueue)); Prodthread.start (); Consthread1.start (); Consthread2.start (); }}
Create a producer thread and two consumer threads.
Extended:
1, Wikipedia:http://en.wikipedia.org/wiki/producer%e2%80%93consumer_problem
2, "chat concurrency--producer and consumer model" Http://www.infoq.com/cn/articles/producers-and-consumers-mode
Java Multithreaded Learning notes: Producer consumer issues