In the front we will have a lot of questions about synchronization, but in reality, there is a need for collaboration between threads. For example, the most classic producer-consumer model: When the queue is full, the producer needs to wait for the queue to have space to continue to put the goods inside, and during the waiting period, the producer must release the seizure rights to the critical resource (that is, the queue). Because producers do not release the use of critical resources, consumers will not be able to consume the goods in the queue, there is no space for the queue, then the producers have been waiting indefinitely. Therefore, in general, when the queue is full, the producer will be handed over to the critical resources of the occupation, and into the suspended state. Then wait for the consumer to consume the goods, and then the consumer informs the producer that the queue has space. Similarly, when the queue is empty, the consumer must wait, waiting for the producer to notify it that there is a product in the queue. This process of communicating with each other is a collaboration between threads.
Today we're going to explore two of the most common ways in which Java threads work together: Using Object.wait (), object.notify (), and using condition
The following is an outline of this article directory:
A. Wait (), notify (), and Notifyall ()
Two. Condition
Three. Implementation of producer-consumer models
If there are any shortcomings please understand, and welcome criticism.
Please respect the author's labor results, reproduced please indicate the original link:
Http://www.cnblogs.com/dolphin0520/p/3920385.html
A. Wait (), notify (), and Notifyall ()
Wait (), notify (), and Notifyall () are methods in the object class:
/**
* Wakes up a single thread that's waiting on this object ' s
* Monitor. If any threads is waiting on the This object, one of the them
* is chosen to be awakened. The choice is arbitrary and occurs at
* The discretion of the implementation. A thread waits on an object ' s
* Monitor by calling one of the wait methods
*/
Publicfinalnativevoidnotify ();
/**
* Wakes up all threads is waiting on this object ' s monitor. A
* Thread waits on a object ' s monitor by calling one of the
* Wait methods.
*/
Publicfinalnativevoidnotifyall ();
/**
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.object#notify ()} method or the
* {@link Java.lang.object#notifyall ()} method for this Object, or a
* Specified amount of time has elapsed.
* <p>
* The current thread is must own this object ' s monitor.
*/
Publicfinalnativevoidwait (longtimeout) throwsinterruptedexception;
The following information can be found from the text descriptions of these three methods:
1) The Wait (), notify (), and Notifyall () methods are local methods and are final methods and cannot be overridden.
2) The Wait () method that invokes an object can cause the current thread to block, and the current thread must have a monitor (that is, a lock) on this object
3) Invoking an object's Notify () method wakes up a thread waiting for the object's monitor, and if more than one thread waits for the object's monitor, only one of the threads can be awakened;
4) Call the Notifyall () method to wake up all the threads that are waiting for this object's monitor;
A friend may have questions about why these three are not methods in the thread class declaration, but rather methods declared in the object class (since the thread class inherits the object class, so thread can also call three methods)? In fact, the problem is simple, because each object has a monitor (that is, lock), so the current thread to wait for an object's lock, of course, this object should be manipulated. Instead of using the current thread, the current thread may be waiting for locks on multiple threads, which can be very complex if manipulated by a thread.
As mentioned above, if you call the Wait () method of an object, the current thread must have the monitor (that is, the lock) of the object, so calling the wait () method must be done either in a synchronous block or in a synchronous method (synchronized block or Synchronized method).
Calling the Wait () method of an object is equivalent to having the current thread hand over the object's monitor, then going into a wait state, waiting for a subsequent lock on the object (the sleep method in the thread class causes the current thread to suspend execution for a period of time, allowing other threads to continue to execute. But it does not release the object lock);
The Notify () method wakes up a thread that is waiting for the object's monitor, and when there are multiple threads waiting for the object's monitor, only one of the threads can be woken up, and it is unclear which thread to wake.
Similarly, the Notify () method of an object is called, and the current thread must have the monitor for that object, so calling the Notify () method must be done either in a synchronous block or in a synchronous method (synchronized block or Synchronized method).
The Nofityall () method can wake all threads that are waiting for the object's monitor, which is different from the Notify () method.
One thing to note here: the Notify () and Notifyall () methods simply wake up the thread that waits for the object's monitor, and do not determine which thread can get to monitor.
As a simple example: if there are three threads Thread1, Thread2, and Thread3 waiting for the monitor of the object Objecta, THREAD4 has the monitor of the object objecta, When the Objecta.notify () method is called in Thread4, only one of Thread1, Thread2, and Thread3 can be awakened. Note that being awakened does not mean that the OBJECTA Monitor is acquired immediately. If the Objecta.notifyall () method is called in Thread4, the three threads of Thread1, Thread2, and Thread3 will be awakened. As for which thread is next able to get to objecta monitor, it depends on the operating system's schedule.
In particular, it is important to note that a thread being awakened does not represent a monitor that immediately acquires the object, but only when the Notify () or Notifyall () is called and exits the synchronized block, and the remaining threads can get lock execution after the object lock is released.
Let's take a look at the following example:
publicclasstest {
Publicstaticobject object =newobject ();
Publicstaticvoidmain (string[] args) {
Thread1 thread1 =newthread1 ();
Thread2 thread2 =newthread2 ();
Thread1.start ();
try{
Thread.Sleep (200);
}catch (Interruptedexception e) {
E.printstacktrace ();
}
Thread2.start ();
}
staticclassthread1extendsthread{
@Override
Publicvoidrun () {
Synchronized (object) {
try{
Object.wait ();
}catch (Interruptedexception e) {
}
SYSTEM.OUT.PRINTLN ("Thread" +thread.currentthread (). GetName () + "acquired to lock");
}
}
}
staticclassthread2extendsthread{
@Override
Publicvoidrun () {
Synchronized (object) {
Object.notify ();
SYSTEM.OUT.PRINTLN ("Thread" +thread.currentthread (). GetName () + "called Object.notify ()");
}
SYSTEM.OUT.PRINTLN ("Thread" +thread.currentthread (). GetName () + "release lock");
}
}
}
No matter how many times it runs, the result must be:
Thread Thread-1 called the object.notify () thread Thread-1 freed the lock thread Thread-0 acquires the lock
Two. Condition
Condition is only present in Java 1.5, it is used to replace the traditional object of Wait (), notify () to implement the collaboration between threads, compared to the Wait (), notify () using object, and the Condition1 await () , signal () is a more secure and efficient way to collaborate between threads. Therefore, it is generally recommended to use the condition, as described in the blocking Queue blog post, where the blocking queue is actually using condition to simulate inter-threading collaboration.
- Condition is an interface, the basic method is the await () and the signal () method;
- Condition relies on the lock interface, generating a condition base code that is Lock.newcondition ()
- The await () and signal () methods that call condition must be within lock protection, meaning they must be between Lock.lock () and Lock.unlock.
Await () in Conditon corresponds to the Wait () of object;
The signal () in condition corresponds to the Notify () of the object;
The Signalall () in condition corresponds to the Notifyall () of the object.
Three. Implementation of producer-consumer models
1. Use the Wait () and notify () of object to implement:
publicclasstest {
Privateintqueuesize = 10;
Privatepriorityqueue<integer> Queue =newpriorityqueue<integer> (queuesize);
Publicstaticvoidmain (string[] args) {
Test test =newtest ();
Producer Producer = Test.newproducer ();
Consumer Consumer = Test.newconsumer ();
Producer.start ();
Consumer.start ();
}
classconsumerextendsthread{
@Override
Publicvoidrun () {
Consume ();
}
Privatevoidconsume () {
while (true) {
Synchronized (queue) {
while (Queue.size () ==0) {
try{
System.out.println ("Queue empty, waiting for data");
Queue.wait ();
}catch (Interruptedexception e) {
E.printstacktrace ();
Queue.notify ();
}
}
Queue.poll (); Remove the first element of the team every time
Queue.notify ();
System.out.println ("Take an element from the queue, queue remaining" +queue.size () + "elements");
}
}
}
}
classproducerextendsthread{
@Override
Publicvoidrun () {
Produce ();
}
Privatevoidproduce () {
while (true) {
Synchronized (queue) {
while (queue.size () = = Queuesize) {
try{
System.out.println ("Queue full, waiting for free space");
Queue.wait ();
}catch (Interruptedexception e) {
E.printstacktrace ();
Queue.notify ();
}
}
Queue.offer (1); Insert one element at a time
Queue.notify ();
SYSTEM.OUT.PRINTLN ("Inserts an element into the queue, the remaining space of the queue:" + (Queuesize-queue.size ()));
}
}
}
}
}
2. Using condition to implement
publicclasstest {
Privateintqueuesize = 10;
Privatepriorityqueue<integer> Queue =newpriorityqueue<integer> (queuesize);
Privatelock lock =newreentrantlock ();
Privatecondition notfull = Lock.newcondition ();
Privatecondition notempty = Lock.newcondition ();
Publicstaticvoidmain (string[] args) {
Test test =newtest ();
Producer Producer = Test.newproducer ();
Consumer Consumer = Test.newconsumer ();
Producer.start ();
Consumer.start ();
}
classconsumerextendsthread{
@Override
Publicvoidrun () {
Consume ();
}
Privatevoidconsume () {
while (true) {
Lock.lock ();
try{
while (Queue.size () ==0) {
try{
System.out.println ("Queue empty, waiting for data");
Notempty.await ();
}catch (Interruptedexception e) {
E.printstacktrace ();
}
}
Queue.poll (); Remove the first element of the team every time
Notfull.signal ();
System.out.println ("Take an element from the queue, queue remaining" +queue.size () + "elements");
}finally{
Lock.unlock ();
}
}
}
}
classproducerextendsthread{
@Override
Publicvoidrun () {
Produce ();
}
Privatevoidproduce () {
while (true) {
Lock.lock ();
try{
while (queue.size () = = Queuesize) {
try{
System.out.println ("Queue full, waiting for free space");
Notfull.await ();
}catch (Interruptedexception e) {
E.printstacktrace ();
}
}
Queue.offer (1); Insert one element at a time
Notempty.signal ();
SYSTEM.OUT.PRINTLN ("Inserts an element into the queue, the remaining space of the queue:" + (Queuesize-queue.size ()));
}finally{
Lock.unlock ();
}
}
}
}
}
Resources:
The idea of Java programming
http://blog.csdn.net/ns_code/article/details/17225469
http://blog.csdn.net/ghsau/article/details/7481142
Source:
Java concurrent Programming: two ways to collaborate between threads: Wait, notify, notifyall, and condition