Java 5 multithreading (III)-lock and condition implement synchronous thread Communication

Source: Internet
Author: User

1> lock:The lock method is more object-oriented than the synchronied method in the traditional thread model. Similar to the lock in life, the lock itself should also be an object. the code segments executed by two threads must be synchronized and mutually exclusive. They must use the same lock object. The lock is in the internal method of the class representing the resource to be operated, rather than in the thread code. the outputer class above can be rewritten as follows: Class outputer2 {

// Declare a lock = new reentrantlock (); Public void print (string name) {// write the code to be mutually exclusive between the lock () and unlock () Methods to lock. lock (); try {for (INT I = 0; I <name. length (); I ++) {system. out. print (name. charat (I);} system. out. println (); // print the string line break} finally {// if an exception is thrown in the middle, the lock will not be unlocked, and others will not be able to enter it. // write the lock in finally. unlock ();}}

}

Read/write locks are divided into read/write locks. Multiple read/write locks are not mutually exclusive. The read/write locks and write locks are mutually exclusive. This is controlled by the JVM. You only need to apply the corresponding locks, if your code read-only data can be read by many people at the same time but cannot be written at the same time, read the lock. If your code modifies data, only one person can write it, and cannot be read at the same time, then write the lock. in short, read locks are applied during reading and write locks when writing! Check the following program: Create 6 threads, 3 threads for reading, 3 threads for writing, and final queue3 Q3 = new queue3 ();

For (INT I = 0; I <3; I ++) {New thread () {public void run () {While (true) {q3.get ();}}}. start (); New thread () {public void run () {While (true) {q3.put (new random (). nextint (10000 ));}}}. start ();

}

Then there is a read method and write method in writing a class queue3: Class queue3 {

Private Object Data = NULL; // shared data. Only one thread can write the data, but multiple threads can read the data at the same time. // Read/write lock readwritelock RWL = new reentrantreadwritelock (); // equivalent to the public void get () {RWL. readlock (). lock (); try {system. out. println (thread. currentthread (). getname () + "be ready to read data! "); Thread. sleep (long) (math. random () * 1000); system. out. println (thread. currentthread (). getname () + "have read data:" + data);} catch (interruptedexception e) {e. printstacktrace ();} finally {RWL. readlock (). unlock () ;}/// equivalent to the write operation public void put (Object Data) {RWL. writelock (). lock (); try {system. out. println (thread. currentthread (). getname () + "be ready to write data! "); Thread. sleep (long) (math. random () * 1000); this. data = data; system. out. println (thread. currentthread (). getname () + "have write data:" + data);} catch (interruptedexception e) {e. printstacktrace ();} finally {RWL. writelock (). unlock ();}}

}

In this way, the normal logic can be implemented. If we comment out the Code related to the read/write locks and find that the program is preparing to write the code, there will be threads reading the code. When we find that the program is preparing to read the code, there are threads to write, which does not conform to our logic. This problem can be easily solved through the new feature of Java 5. view the classic (cache) usage of the Java API reentrantreadwritelock. this is the above pseudo code. class cacheddata {
Object Data;
Volatile Boolean cachevalid;
Final reentrantreadwritelock RWL = new reentrantreadwritelock ();

Void processcacheddata (){
RWL. readlock (). Lock ();
If (! Cachevalid ){
// Must release read lock before acquiring write lock
RWL. readlock (). Unlock ();
RWL. writelock (). Lock ();
Try {
// Recheck state because another thread might have
// Acquired write lock and changed state before we did.
If (! Cachevalid ){
Data =...
Cachevalid = true;
}
// Downgrade by acquiring read lock before releasing write lock
RWL. readlock (). Lock ();
} Finally {
RWL. writelock (). Unlock (); // unlock write, still hold read
}
}
Try {
Use (data );
} Finally {
RWL. readlock (). Unlock ();
}
}
} Based on the above example, we can implement a cache system. Map <string, Object> cache = new hashmap <string, Object> (); readwritelock rrwl = new reentrantreadwritelock ();

Public object getdata (string key) {rrwl. readlock (). lock (); object value = NULL; try {value = cache. get (key); If (value = NULL) {rrwl. readlock (). unlock (); rrwl. writelock (). lock (); try {// assume that the three threads get the write lock at the same time. We know that only the first thread can get the write lock. // then the other two threads have to wait, if the first thread completes the execution by flow, the two threads can get the write lock, // then the data can be modified (Value assignment ). so add judgment! If (value = NULL) {// Why Should I judge it here .? Value = "Hello World";} // downgrade, obtain the read lock rrwl before releasing the write lock. readlock (). lock ();} finally {rrwl. writelock (). unlock () ;}} finally {rrwl. readlock (). unlock ();} return value;

}

2> condition:The condition function is similar to the traditional thread technology, object. wait () and object. when waiting for condition, the function of notify () allows "false Wakeup". This is usually used as a concession to the basic platform semantics, which has little practical impact on most applications, this is because condition should always be waited in a loop and testing the State declaration being waited. A certain implementation can remove possible false wakeup at will, but it is recommended that programmers always assume that these false wakeup may happen, so they always wait in a loop. A lock can have multiple conditions, that is, multiple waits and notifications. For more information, see the application cases of blocking queues implemented by lock and condition provided by jdk1.5, we also need to understand the object-oriented encapsulation. in the traditional thread mechanism, a single monitor object can only have one waiting and notification. To implement multiple waiting and notification, multiple synchronous monitor objects must be nested. (if only one condition is used, both are waiting. Once one is put in, it will notify you that the other may proceed ). we can also implement the above example through lock and condition: The sub-thread loops 10 times, then the main thread loops 100, and then returns to the sub-thread loop 10 times, and then returns to the main thread and loops 100 again, so that the loop is 50 times, please write the program.Here we only implement one of the methods, because the others are the same. Lock lock = new reentrantlock ();

Condition condition = lock. newcondition (); // The default sub-thread executes Boolean isshouldsub = true first; Public void sub (int K) {lock. lock (); // equivalent to synchronied try {While (! Isshouldsub) {try {condition. await (); // then implement communication} catch (interruptedexception e) {e. printstacktrace () ;}}for (INT I = 1; I <= 10; I ++) {system. out. println ("sub thread sequence" + I + "loop of" + k);} // when the sub-thread is finished, set it to false isshouldsub = false; // and wake up the main thread condition. signal ();} finally {lock. unlock ();}

}

You can use lock and condition to implement a Buffer Queue (to distinguish the buffer from the cache). In fact, the jdk api has the following example: Class boundedbuffer {
Final lock = new reentrantlock ();
Final condition notfull = Lock. newcondition ();
Final condition notempty = Lock. newcondition ();

Final object [] items = new object [2, 100];
Int putptr, takeptr, count;

Public void put (Object X) throws interruptedexception {
Lock. Lock ();//Step 1: implement mutual exclusion
Try {
While (COUNT = items. Length) // if it is not put in the array, the thread is blocked.
Notfull. Await ();
Items [putptr] = X;
If (++ putptr = items. length) putptr = 0; // If putptr is already the last of the array, set putptr to 0 and add the total number to + + count from the first one. //
Notempty. Signal ();//Notify other threads to obtain
} 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 ();
}

}
}
This logic is easy to understand, but we can see that the above program uses two conditions? It seems that a condition can also be used to implement. Public void put (Object X) throws interruptedexception {// if five threads execute this method, only one thread obtains the lock.
Lock. Lock ();// When other threads are locked, they cannot come in, including the following take () because they use the same lock.
Try {// If it is full
While (COUNT = items. length)
Notfull. Await(); // When the lock is executed, the lock is released. There may be five threads waiting here. Other threads can call the take () method to obtain the lock and then call signal () however, only one of the five threads can be awakened. this wake-up thread wakes up other threads when it is executed to signal. if a condition is used, the above four threads may be awakened, and the four threads are put, but the take () thread should be awakened. because it is full. If the thread is notified again, a logic error occurs. so here we use the advantages of two condition!
Items [putptr] = X;
If (++ putptr = items. Length) putptr = 0;
++ Count;
Notempty. Signal ();
} Finally {
Lock. Unlock ();
}

} Accordingly, we can changeThe sub-thread loops 10 times, then the main thread loops 100, and then returns to the sub-thread loop 10 times, and then returns to the main thread and loops 100 again, so that the loop is 50 times, please write the program.In this example, the jump between two threads is implemented. If the round robin between three threads is realized, for example, thread 1 loop 10, thread 2 loop 100, thread 3 loops 20 times, then thread 1, and then thread 2... it has been circulating for 50 times. class business3 {

Lock = new reentrantlock (); condition sub1 = lock. newcondition (); condition sub2 = lock. newcondition (); condition sub3 = lock. newcondition (); // The default thread 1 executes int shouldsub = 1; Public void sub1 (int K) {lock. lock (); // equivalent to synchronied try {While (shouldsub! = 1) {try {sub1.await (); // then implement communication} catch (interruptedexception e) {e. printstacktrace () ;}}for (INT I = 1; I <= 10; I ++) {system. out. println ("sub1 thread sequence" + I + "loop of" + k);} // set the value to 2, and thread 2 can execute shouldsub = 2; // After thread 1 is finished, only thread 2 sub2.signal ();} finally {lock. unlock () ;}} public void sub2 (int K) {lock. lock (); try {While (shouldsub! = 2) {try {sub2.await ();} catch (interruptedexception e) {e. printstacktrace () ;}}for (INT I = 1; I <= 100; I ++) {system. out. println ("sub2 thread sequence" + I + "loop of" + k);} // set the value to 3. Thread 3 can execute shouldsub = 3; // After thread 2 is finished, only thread 3 sub3.signal ();} finally {lock. unlock () ;}} public void sub3 (int K) {lock. lock (); try {While (shouldsub! = 3) {try {sub3.await ();} catch (interruptedexception e) {e. printstacktrace () ;}}for (INT I = 1; I <= 20; I ++) {system. out. println ("sub3 thread sequence" + I + "loop of" + k);} // set the value to 1. Thread 1 can execute shouldsub = 1; // After thread 3 is finished, only thread 1 sub1.signal ();} finally {lock. unlock ();}

}

Reprinted please indicate the source: http://blog.csdn.net/johnny901114/article/details/8695708

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.