A. lock can be used instead of the Synchronized keyword to implement mutex functionality. Here's how to use it:
Lock L = ...; L.lock (); try { //access the resource protected by this lock } finally { l.unlock (); }
It's important to note that.
1. One or more methods that require mutual exclusion to use the same mutex.
2. In the block of code that is contained in the lock, use the finally block to release the lock.
Two. Condition's await method (note that it is not a wait method) can replace the wait method in traditional communication, and the corresponding signal method replaces the notify.
When judging the condition of traditional communication, we use while rather than if to make the condition judgment, it is for false awakening. So what is False awakening?
False wake-up is: We require the AB method to execute sequentially, there are 5 threads execute a, 5 threads execute B, if all a waits at some point, when A1 is awakened and executes the code, the Notify method is called, which is intended to wake up the B module execution thread, but because AB is a common lock, So it's possible to wake up a, that is, to wake up the code that should not be executed, which is false wakeup.
So we use the while condition, and even if it wakes up, we do a conditional interpretation, so that the code that is falsely awakened will wait again.
This requires the programmer to control the error of avoiding false wakes. and lock and condition to help us solve this problem. There can be more than one condition inside a lock. So the same lock can be implemented in multiple condition modules
Switch between, as in the above example A1 after the execution, through B corresponding to the condtion.signal can only wake up b corresponding thread. We can take a look at the example in the condition API to block the simple implementation of the queue:
First we look at the traditional communication technology to achieve a simple blocking queue, what are the drawbacks?
Package Com.lipeng;import Java.util.random;public class BoundedBuffer1 <t>{private object[] objs=new object[100] ;p rivate int length;private int putindex=0;//save pointer private int getindex=0;//pointer/** * Store element, from beginning to end, and back and forth * @param t */public Sy nchronized void put (T-t) {//If it is full, wait. while (length==objs.length)//If n threads wait here, after one of the threads is awakened, execute the following code, the 35 line this.notify is intended to wake up the thread fetching the data, but may actually wake the memory thread. {try {this.wait ();} catch (Interruptedexception e) {//TODO auto-generated catch Blocke.printstacktrace ()}} objs[putindex]=t; Insert element length++ at the end of the team; Length plus 1,putindex++;if (putindex==objs.length) {//Note that it is not full before it is placed from the beginning, but instead holds the pointer to the end of the team and starts from scratch. putindex=0;} This.notify ();} /** * Take elements, take them from beginning to end, and repeat them. * @return */public synchronized T get () {while (length==0) {try {this.wait ();} catch (Interruptedexception e) {//TODO auto-g Enerated catch Blocke.printstacktrace ();}} T t= (t) objs[getindex];length--;getindex++;if (getindex==objs.length) {getindex=0;} This.notify (); return t;} public static void Main (string[] args) {final boundedbuffer1<integer> bb=newBoundedbuffer1<integer> (); Runnable getrun=new Runnable () {@Overridepublic void Run () {for (int i=0;i<10;i++) {synchronized (BB) {// Add synchronized here just to keep the read data and print data intact, do the demo with an integer Data=bb.get (); System.out.println (Thread.CurrentThread (). GetName () + "read element------" +data);}}}; Runnable putrun=new Runnable () {@Overridepublic void Run () {for (int i=0;i<10;i++) {synchronized (BB) {// This adds synchronized just to keep the data and print data intact, making a presentation with an integer data=new Random (). Nextint (); bb.put (data); System.out.println (Thread.CurrentThread (). GetName () + "put---------------------------" +data);}}}; System.out.println ("***********************"); for (int i=0;i<10;i++) {new Thread (Getrun). Start (); New Thread ( Putrun). Start ();}}}
How do we come to see how condition helped us achieve this?
Package Com.lipeng;import Java.util.random;import Java.util.concurrent.locks.condition;import Java.util.concurrent.locks.lock;import Java.util.concurrent.locks.reentrantlock;public class BoundedBuffer2 <T >{private object[] objs=new object[100];p rivate int length;private int putindex=0;//save pointer private int getindex=0;// Take the pointer private Lock lock=new reentrantlock ();p rivate Condition putcon=lock.newcondition ();//Storage conditions Private Condition getcon= Lock.newcondition ();//conditions/** * storage elements, from beginning to end, and then repeatedly from beginning to end * @param t */public void put (T t) {try {lock.lock ();//If it is full, wait. while (length==objs.length)//If n threads wait here, after one of the threads is awakened, execute the following code, the 35 line this.notify is intended to wake up the thread fetching the data, but may actually wake the memory thread. {try {putcon.await ();} catch (Exception e) {//TODO auto-generated catch Blocke.printstacktrace ()}} objs[putindex]=t; Insert element length++ at the end of the team; Length plus 1,putindex++;if (putindex==objs.length) {//Note that it is not full before it is placed from the beginning, but instead holds the pointer to the end of the team and starts from scratch. putindex=0;} Getcon.signal (); System.out.println (Thread.CurrentThread (). GetName () + "put---------------------------" +t); catch (ExceptIon e) {//TODO auto-generated catch Blocke.printstacktrace ();} Finally{lock.unlock ();}} /** * Take elements, take them from beginning to end, and repeat them. * @return */public T get () {try {lock.lock (); while (length==0) {try {getcon.await ()} catch (Exception e) {//TODO Auto-gener Ated catch Blocke.printstacktrace ();}} T t= (t) objs[getindex];length--;getindex++;if (getindex==objs.length) {getindex=0;} Putcon.signal (); System.out.println (Thread.CurrentThread (). GetName () + "read element------" +t); return t;} catch (Exception e) {//TODO auto-generated catch Blocke.printstacktrace (); return null;} Finally{lock.unlock ();}} public static void Main (string[] args) {final boundedbuffer2<integer> bb=new boundedbuffer2<integer> (); Runnable getrun=new Runnable () {@Overridepublic void Run () {for (int i=0;i<10;i++) {bb.get ()}}}; Runnable putrun=new Runnable () {@Overridepublic void Run () {for (int i=0;i<10;i++) {Integer data=new Random (). Nextint ( Bb.put (data);}}; System.out.println ("***********************"); for (int i=0;i<10;i++) {New Thread (gEtrun). Start (); new Thread (Putrun). Start ();}}
Precautions:
Lock (including read-write lock) +condition looks more object-oriented and also seems to improve performance * (because I have not verified, haha) is also more rigorous, but I think if the traditional communication method enough, there is no need to use it.
Java Multi-Threading and concurrency Application-(9)-Lock lock+ Conditional blocking Conditon implementing thread synchronous communication