JAVA course 27th (multi-thread (6)-Multi-producer and multi-consumer questions (JDK1.5 new features) and jdk1.5 New Features
Multiple producers and consumers
Take the production of steamed bread for example.
Class Resource {private String name; private int count = 1; private boolean flag = false; public synchronized void set (String name) {if (flag) {try {this. wait ();} catch (Exception e) {// TODO: handle exception} this. name = name + count; count ++; System. out. println (Thread. currentThread (). getName () + "--- producer ----" + this. name); flag = true; y ();} public synchronized void out () {if (! Flag) {try {this. wait ();} catch (Exception e) {// TODO: handle exception} System. out. println (Thread. currentThread (). getName () + "--------- consumer --------" + this. name); flag = false; y () ;}} class Producer implements Runnable {private Resource r; Producer (Resource r) {this. r = r;} public void run () {while (true) {r. set ("steamed bread") ;}} class Consumer implements Runnable {private Resource r; Consumer (Resource r) {this. r = r;} public void run () {while (true) {r. out () ;}} public class Main {public static void main (String [] args) {Resource r = new Resource (); Producer pro = new Producer (r ); consumer con = new Consumer (r); Thread t0 = new Thread (pro); Thread t1 = new Thread (pro); Thread t2 = new Thread (con ); thread t3 = new Thread (con); t0.start (); t1.start (); t2.start (); t3.start ();}}
The above code is prone to a problem, that is, the same steamed bread is consumed multiple times, or some steamed bread is not consumed. This problem does not occur to individual consumers.
Cause: the thread wake up by notify is any one. For example, t0 t1 is in the waiting state. After t0 is active, t1 may also be awakened, therefore, multiple steamed buns are generated but not consumed. To solve this problem, the flag can be changed to a loop, which may easily lead to a deadlock: t0 t1 is wait, t2 is consumed once normally, flag = false, wake up t0, because cycle t2 t3 is wait, t0 is executed once, flag = true, suppose wake up t1, Judge t0 for wait, while, t1 also enters the waiting and deadlock status
PS: After a frozen thread is awakened, it does not participate in judgment and is executed downward. Therefore, in simple words, multiple steamed buns are not consumed, the reason is that the frozen thread no longer participates in the judgment, and the deadlock is caused by loop judgment.
Multi-production and multi-consumption solutions:
Y, changed to notifyAll. After one of the current threads in this class is executed normally, all threads are awakened. Because of the while, the other thread will naturally wait and execute it once, the remaining thread of the other party continues to wait, so that the corresponding consumption is generated.
Class Resource {private String name; private int count = 1; private boolean flag = false; public synchronized void set (String name) {while (flag) {try {this. wait ();} catch (Exception e) {// TODO: handle exception} this. name = name + count; count ++; System. out. println (Thread. currentThread (). getName () + "--- producer ----" + this. name); flag = true; policyall ();} public synchronized void out () {while (! Flag) {try {this. wait ();} catch (Exception e) {// TODO: handle exception} System. out. println (Thread. currentThread (). getName () + "--------- consumer --------" + this. name); flag = false; policyall ();}}
Summary:
If, only once, it is easy to cause the thread that should not be awakened to be awakened, and problems may occur.
While judge whether to run after the thread obtains the execution right
Notify, can only wake up any thread, but it does not make sense to wake up the local thread, and while + notify = deadlock
NotifyAll, the thread will wake up the thread
Therefore, the problem of multi-production and multi-consumption is = while + policyall, but it also causes low efficiency (this party should not wake up or be awakened)
New features (JDK1.5 upgrade)
How can we not wake the local party up, but only the other party?
Void Fu () // The previous {synchronized (obj) // The lock operation is implicit, and only the lock itself knows {code ....}} // After the upgrade, the Lock is encapsulated into the object Lock L = new ReentrantLock (); and the implicit method of the Operation Lock is defined in the object void Fu () {L. lock (); // get the lock code .. l. unlock (); // release the lock}
Interface Lock
Lock
The implementation providessynchronized
Methods and statements can obtain a wider range of lock operations. This implementation allows a more flexible structure, can have very different attributes, can support multiple relatedCondition
Object.
Condition
SetObject
Monitor method (wait
,notify
AndnotifyAll
) Into different objects, so thatLock
To provide multiple waiting sets (wait-set) for each object ). Where,Lock
Replacedsynchronized
Use of methods and statements,Condition
Replaces the use of the Object monitor method.
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
Lock interface: replaces the synchronous code block or synchronous function, and changes the implicit operation of the Synchronous Lock into a real operation. It is more flexible. You can add multiple monitors with one Lock.
Method:
L. lock (); // obtain the lock
L. unlock (); // release the lock, which is generally used with the finally code block.
Condition interface: implements the wait (), Y (), and policyall () methods in the Object. These monitor methods are encapsulated separately and become the Condition monitor Object. Any locks can be combined.
Await () is equivalent to wait
Signal () is equivalent to running y
SignalAll (); equivalent to policyall
Import java. util. concurrent. locks. *; class Resource {private String name; private int count = 1; private boolean flag = false; // create a Lock L = new ReentrantLock (); // obtain the lock monitor object (Condition) through an existing lock // Condition con = L. newCondition (); // obtain two sets of monitors through the existing lock, one monitoring producer and the other monitoring consumer. Condition pro_con = L. newCondition (); Condition consu_con = L. newCondition (); public void set (String name) {L. lock (); try {while (flag) {try {pro_con. Await (); // thread freeze} catch (Exception e) {// TODO: handle exception} this. name = name + count; count ++; System. out. println (Thread. currentThread (). getName () + "--- producer 5.0 ----" + this. name); flag = true; // con. signalAll (); // wake up All threads consu_con.signal (); // wake up the consumer thread without All} catch (Exception e) {// TODO: handle exception} finally {L. unlock (); // release lock} public void out () {L. lock (); try {while (! Flag) {try {consu_con.await ();} catch (Exception e) {// TODO: handle exception} System. out. println (Thread. currentThread (). getName () + "--------- consumer 5.0 --------" + this. name); flag = false; // con. signalAll (); pro_con.signal ();} catch (Exception e) {// TODO: handle exception} finally {L. unlock () ;}} class Producer implements Runnable {private Resource r; Producer (Resource r) {this. r = r;} public void run () {while (true) {r. set ("steamed bread") ;}} class Consumer implements Runnable {private Resource r; Consumer (Resource r) {this. r = r;} public void run () {while (true) {r. out () ;}} public class Main {public static void main (String [] args) {Resource r = new Resource (); Producer pro = new Producer (r ); consumer con = new Consumer (r); Thread t0 = new Thread (pro); Thread t1 = new Thread (pro); Thread t2 = new Thread (con ); thread t3 = new Thread (con); t0.start (); t1.start (); t2.start (); t3.start ();}}
The actual development is such a code
Class BoundedBuffer {// buffer final Lock lock = new ReentrantLock (); final Condition notFull = lock. newCondition (); final Condition notEmpty = lock. newCondition (); final Object [] items = new Object [100]; // create a large container: int putptr, takeptr, count; public void put (Object x) throws InterruptedException {lock. lock (); try {while (count = items. length) notFull. await (); items [putptr] = x; if (++ putptr = items. length) putptr = 0; ++ count; notEmpty. signal ();} finally {lock. unlock () ;}} public Object take () throws InterruptedException {lock. lock (); try {while (count = 0) notEmpty. await (); Object x = items [takeptr]; if (++ takeptr = items. length) takeptr = 0; -- count; notFull. signal (); return x;} finally {lock. unlock ();}}}
Java multi-producer-Multi-Consumer problem (+ high score)
The producer places a random integer into the blocked Queue (different queues can be provided for two consumers), and the consumer extracts elements from the queue for determination. BlockingQueue can be used for synchronization, which is convenient, you just need to write a static method to determine the prime number and number of workers ~ Let's talk about the code.
Import java. util. ArrayList;
Import java. util. Arrays;
Import java. util. List;
Import java. util. concurrent. ArrayBlockingQueue;
Import java. util. concurrent. BlockingQueue;
Import java. util. concurrent. Define blockingqueue;
Public class Producer extends Thread
{
Private List <BlockingQueue <Integer> queueList;
Public Producer (List <BlockingQueue <Integer> bQueueList)
{
This. queueList = bQueueList;
}
Public void run ()
{
Int count = 0;
While (count ++ <10)
{
Int randomInt = (int) (Math. random () * 100 + 1 );
Try
{
For (BlockingQueue <Integer> queue: queueList)
{
Queue. put (randomInt );
}
System. out. println (randomInt + "is put ..");
}
Catch (InterruptedException e)
{
Thread. currentThread (). interrupt ();
}
}
}
Public static void main (String [] args)
{
BlockingQueue <Integer> bQueue = new LinkedBlockingQueue <Integer> ();
BlockingQueue <Integer> bQueueCopy = new LinkedBlockingQueue <Integer> ();
List <BlockingQueue <Integer> list = new ArrayList <BlockingQueue <Integer> ();
List. add (bQueue );
List. add (bQueueCopy );
... The remaining full text>
Java multi-thread producer-consumer issues
It is null or full. If the container is not customized, it is necessary to determine whether the container is full before each production in the Thread class (this is determined by the container ), determine whether the container is empty during consumption.
2. Generally, it is best to use the synchronized keyword to lock the synchronization code for thread synchronization, and then use the wait () and Y () methods to achieve thread synchronization, but the effect can be seen only when the container capacity is large. The Code is as follows:
Class BQProduc implements Runnable {
Private BlockingQueue <Integer> queue;
Public BQProduc (BlockingQueue <Integer> queue ){
This. queue = queue;
}
Public void run (){
Synchronized (queue ){
For (int product = 1; product <= 10; product ++ ){
Try {
If (queue. size () = 5 ){
Queue. wait ();
}
Queue. put (product); // put it in one
System. out. println ("put -->" + this. queue. size ());
Queue. Sort y ();
} Catch (InterruptedException e ){
E. printStackTrace ();
}
}
}
}
}
Class BQConsume implements Runnable {
Private BlockingQueue <Integer> queue;
Public BQConsume (BlockingQueue <Integer> queue ){
This. queue = queue;
}
Public void run (){
Synchronized (queue ){
For (int I = 1; I <= 10; I ++ ){
Try {
If (queue. isEmpty ()){
Queue. wait ();
}
System. out. println ("out <--" + this. queue. size ());
Queue. take (); // get one
Queue. Sort y ();
} Catch (InterruptedException e ){
E. printStackTrace ();
}
}
}
}
}
Running result:
Put in --> 1
Put in --> 2
Put in --> 3
Put in --> 4
Put in --> 5
Extract <-- 5
Extract <-- 4
Extract <-- 3
Extract <-- 2
Extract <-- 1
Put in --> 1
Put in --> 2
Put in --> 3
Put in --> 4
Put in --> 5
Extract <-- 5
Extract <-- 4
Extract <-- 3
Extract <-- 2
Extract <-- 1
PS: when the base number is large to a certain extent, you can see the desired result.
3. If you must... the remaining full text>