Producer-consumer model is one of the important contents of interprocess communication. The principle is very simple, but the implementation of their own language is often a lot of problems, the following we use a series of code to show the problem in coding and the best solution.
/* Single-producer, single-consumer production of roast duck * *
Classresource{PrivateString name; Private intCount = 1; Counter, recording how many ducks were produced and consumedPrivate BooleanFlag =false; Stop Mark Public synchronized voidset (String name)//produce roast Duck method { while(flag)//If flag=true, wait {Try{ This. Wait ();}Catch(Interruptedexception e) {}//using the Wait () method must catch an exception} This. Name = name +count; Count++; System.out.println (Thread.CurrentThread (). GetName ()+"..."+ This. Name); Flag=true; After producing a roast duck, set flag to true, waiting for consumers to consume roast duck
Notify (); Wake-Up Consumer} Public synchronized voidout () { while(!flag) { Try{ This. Wait ();}Catch(Interruptedexception e) {}} System.out.println (Thread.CurrentThread (). GetName ()+"........."+ This. Name); Flag=false; After consuming a roast duck, the flag is set to false, waiting for the producer to produce roast duck notify (); Wake-Up producer}}classProducerImplementsrunnable{Resource R; Producer (Resource r) { This. R =R; } Public voidrun () { while(true) {R.set ("Kaoya"); Production of Roast Duck} }}classConsumerImplementsrunnable{Resource R; Consumer (Resource r) { This. R =R; } Public voidrun () { while(true) {r.out (); Consumption of Roast Duck}}} Public classresourcedemo{ Public Static voidMain (string[] args) {Resource R=NewResource (); Producer Producer=NewProducer (R); Consumer Consumer=NewConsumer (R); Thread T1=NewThread (producer); Thread T2=NewThread (producer);T1.start (); T2.start (); }}
The above is a single-producer single-consumer code, we look at the results of the operation:
However, as is the case, it is impossible to have only one cook in the kitchen of a restaurant, nor can there be only one customer, so it is meaningless to consider single-consumer single producers. Let's add a consumer and producer thread.
Obviously, there is a deadlock in the operation, the program stuck, which is very confusing.
In fact, when you join two threads, the whole process has changed a lot. The starting flag is false, so the producer thread T1 can enter the synchronization area, and the flag is set to true after completion. In this case, the producer thread T3 enters the wait state. At the same time, two consumer threads T2 and T4 may enter the wait state because of a start flag of false. When thread T1 completes the entire process preparation notify (), there are three threads in the line constructor: producer T3, Consumer T2, T4. Since notify () works by randomly waking up a thread, the most unfortunate case is that if it wakes up a producer thread T3, then T3 determines that flag is true and then enters the wait state. At this point, all four threads will enter the wait state, and thread deadlock naturally occurs.
So how to solve? The simplest way is to change notify () to Notifyall () so that each time it wakes up all the threads. However, this approach is a bit of a waste of resources, because we only need to wake up 1 or 2 threads, and using Notifyall () will have to wake up three threads. There must be a problem with the interview-how to optimize it?
We can use JDK1.5 's feature lock to handle it, we need to use it in the head import java.util.concurrent.locks.*, it can realize only the wake-up consumer thread or producer thread, give the programmer more control, Nature can also improve the efficiency of the program, making it unnecessary to wake up threads that do not need to wake. The specific code is as follows:
Importjava.util.concurrent.locks.*;classresource{PrivateString name; Private intCount = 1; Private BooleanFlag =false; Lock Lock=NewReentrantlock (); New Lock Object Condition Producer_con=lock.newcondition (); New producer Condition Condition Consumer_con=lock.newcondition (); New consumer condition Public voidset (String name) {Lock.lock (); LockedTry { while(flag) {Try{producer_con.await ();}Catch(Interruptedexception e) {}//Note In this case the original this.wait () should be changed to producer_con.await} This. Name = name +count; Count++; System.out.println (Thread.CurrentThread (). GetName ()+"..."+ This. Name); Flag=true; Consumer_con.signal (); Wake up Consumer Thread}finally{lock.unlock (); Put the unlock in the Finally, regardless of whether there is an exception in the middle must be unlocked}} Public voidout () {lock.lock (); Try { while(!flag) { Try{consumer_con.await ();}Catch(Interruptedexception e) {}} System.out.println (Thread.CurrentThread (). GetName ()+"........."+ This. Name); Flag=false; Producer_con.signal (); Wake producer Thread}finally{lock.unlock (); } }}classProducerImplementsrunnable{Resource R; Producer (Resource r) { This. R =R; } Public voidrun () { while(true) {R.set ("Kaoya"); } }}classConsumerImplementsrunnable{Resource R; Consumer (Resource r) { This. R =R; } Public voidrun () { while(true) {r.out (); } }} Public classresourcedemo{ Public Static voidMain (string[] args) {Resource R=NewResource (); Producer Producer=NewProducer (R); Consumer Consumer=NewConsumer (R); Thread T1=NewThread (producer); Thread T2=NewThread (consumer); Thread T3=NewThread (producer); Thread T4=NewThread (consumer); T1.start (); T2.start (); T3.start (); T4.start (); }}
The result of the operation, such as silk-like smooth:
Java implementation of multi-threading producer consumption model and optimization scheme