Thread (2) _ inter-thread Communication
Inter-thread communication: multiple threads process the same resource, but the tasks are different.
I. Waiting for wake-up Mechanism
Methods involved:
1. wait (); The thread is frozen, and the thread that is wait will be stored in the thread pool.
2. Wake y (); wake up any thread in the thread pool
3. yyall (); wake up all threads in the thread pool
These methods must be defined in synchronization, because these methods are used to operate the thread state, and you must specify which lock thread to operate on.
Wait () can only use the notify of lock A to wake up the thread. The thread after wait can be considered to be placed in the thread pool.
Why is the thread method wait policy policyall defined in the Object class?
Because these methods are monitor methods, the monitor is actually a lock.
A lock can be a multi-person Object, and any Object call method must be defined in the Object.
Package com. test2; 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 (InterruptedException e) {} 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 (InterruptedException e) {} 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 ("roast duck") ;}} class Consumer implements Runnable {private Resource r; Consumer (Resource r) {this. r = r;} public void run () {while (true) {r. out () ;}} public class Demo {public static void main (String [] args) {Resource r = new Resource (); Producer a = new Producer (r ); consumer B = new Consumer (r); Thread t0 = new Thread (a); Thread t1 = new Thread (B); t0.start (); t1.start ();}}
The result is that one is consumed for each production.
Ii. Multi-producer and multi-consumer issues
Change the code to two producers and two consumers:
Thread t0 = new Thread ();
Thread t1 = new Thread ();
Thread t2 = new Thread (B );
Thread t3 = new Thread (B );
T0.start ();
T1.start ();
T2.start ();
T3.start ();
As you can see, there are still security issues. The key lies in this Code:
If (flag)
Try {this. wait ();} catch (InterruptedException e) {}// t0 t1
When t0 t1 is held by wait (), when it is awakened again, it will not judge the flag again, but directly go down to production again, leading to errors.
You only need to change the if statement to the while statement so that it can return and judge again.
While (flag)
Try {this. wait ();} catch (InterruptedException e ){}
But after the code is changed to this way, the deadlock problem occurs:
When the result is run, it will become stuck.
Cause:When t0 (active), t1, t2, t3, t0 goes through the thread code, wake up is not one in the middle of t2 or t3, but t1, and the flag is changed to true, then t1 is directly wait.
At present, t0, t1, t2, and t3 are all dead and will not be awakened, resulting in deadlocks. The reason for the above deadlock is that the if statement is used to wake up the program and then go down. The program will always commit y to any thread instead
When all threads are wait, when the while is used, the flag is determined first, and it will be directly suspended (the thread of the same party is awakened ).
The reason is that the thread of the other party is not awakened. So how can we ensure that at least one thread of the other can be awakened each time?
Sorry, but there is no way to wake up the specified thread. You can consider changing notify to yyall to wake up all wait threads each time to solve the problem! Once again, one will be consumed for each production.
Summary:
If judgment mark, only once, will cause the thread that should not run to run, data error.
The while flag resolves whether the thread needs to run after obtaining the execution right.
NotifyAll solves the problem that the local thread will surely wake up the thread of the other party. notify may only wake up the local thread, Which is meaningless. And the while Mark + running y will cause a deadlock.
Therefore, when multiple producers and consumers are involved, use while + policyall.
Problem:The local thread may be awakened when the notifyAll is used to wake up the thread. However, it is meaningless (inefficient) to wake up the local thread. The local thread has finished its work, you just need to wake up the other thread to work.
The interface Lock is provided in jdk1.5 java. util. concurrent. locks.
The Lock implementation provides a wider range of Lock operations than the synchronized Method and statement.
In the synchronous code block, the lock operation is implicit, and the acquisition and release are both implicit. After jdk1.5, the lock and synchronization are encapsulated into objects, and the operation lock is displayed in an object-oriented manner.
Object obj = new Object ();
Void show ()
{Synchronized (obj)
{
}
}
Changed:
Lock lock = new ReetrantLock (); // mutex Lock, which cannot be obtained by other threads after being acquired by one thread.
Void show ()
{Lock. lock (); // obtain the lock
Code...
Lock. unlock (); // release the lock
}
Interface Conditionn splits the Object monitor methods (wait, policy, and policyall) into distinct objects for use in combination with any lock.
Lock replaces the synchronized Method and statement, and conditiont replaces the Object monitor method.
The Condition instance is essentially bound to a Lock. To obtain the Condition instance for the Lock instance, use the newCondition () method.
Solution to the above problem: the producer and consumer respectively obtain a condition object and each has a set of monitor methods. The producer specifies the consumer to wake up, and the consumer specifies the producer to wake up.
The modified code is as follows:
Class Resource1 {private String name; private int count = 1; private boolean flag = false; // create a lock object. Lock lock = new ReentrantLock (); // obtain the monitor object of the lock through the existing Lock // Condition con = lock. newCondition (); // obtain two sets of monitors through an existing lock, one for monitoring producers, and the other for monitoring consumer Condition producer_con = lock. newCondition (); Condition consumer_con = lock. newCondition (); public void set (String name) {lock. lock (); try {while (flag) // if () try {producer_con.await ();} catch (InterruptedException e) {} this. name = name + count; count ++; System. out. println (Thread. currentThread (). getName () + ".... "+" producer "+ ".... "+ this. name); flag = true; consumer_con.signal (); // using Y ()} finally {lock. unlock () ;}} public void out () {lock. lock (); try {while (! Flag) // if () try {consumer_con.await ();} catch (InterruptedException e) {} System. out. println (Thread. currentThread (). getName () + ".... "+" consumer "+ ".... "+ this. name); flag = false; producer_con.signal (); // using Y ()} finally {lock. unlock () ;}} class Producer1 implements Runnable {private Resource r; Producer1 (Resource r) {this. r = r;} public void run () {while (true) {r. set ("roast duck") ;}} class Consumer1 implements Runnable {private Resource r; Consumer1 (Resource r) {this. r = r;} public void run () {while (true) {r. out () ;}} public class LockDemo {public static void main (String [] args) {Resource r = new Resource (); Producer a = new Producer (r ); consumer B = new Consumer (r); Thread t0 = new Thread (a); Thread t1 = new Thread (a); Thread t2 = new Thread (B ); thread t3 = new Thread (B); t0.start (); t1.start (); t2.start (); t3.start ();}}View Code
Summary:
* Lock interface: A synchronization code block or function is replaced. Convert the implicit synchronization operation to the display Lock operation. At the same time, it is more flexible. Multiple sets of monitors can be added to one lock.
* Lock (): Get the lock
* Unlock (): Release the lock, which must be defined in the finally code block.
* Condition interface: The wait prepare y policyall method in the Object is replaced. These monitor methods are encapsulated separately and become the Condition monitor Object.
* Any locks can be combined.
* Await () -- wait ()
* Signal () -- returns y ()
* SignalAll () -- policyall ()
Example: Assume there is a bound buffer, which supportsput
Andtake
Method. If you try to executetake
Operation, the thread will be blocked until a certain item becomes available;
If you try to executeput
The thread will be blocked until the space becomes available.
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; 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(); } } }