Java multithreading-Lock/Condition,-lockcondition
In java1.5, Lock objects are used to achieve synchronization, which is more convenient to use.
Use ReentrantLock for synchronization
public class MyService { private Lock lock = new ReentrantLock(); public void methodA(){ try { lock.lock(); System.out.println("methodA begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodA end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void methodB(){ try { lock.lock(); System.out.println("methodB begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodB end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}public class Test { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); new Thread(()->service.methodA()).start(); new Thread(()->service.methodA()).start(); new Thread(()->service.methodB()).start(); new Thread(()->service.methodB()).start(); }}
View Code
Test results: the thread that calls lock. lock () holds the "Object monitor". Other threads only compete for the lock when it is released. The effect is the same as that of synchronized.
methodA begin threadName=Thread-0 time=1516242293668methodA end threadName=Thread-0 time=1516242298669methodA begin threadName=Thread-1 time=1516242298669methodA end threadName=Thread-1 time=1516242303671methodB begin threadName=Thread-2 time=1516242303671methodB end threadName=Thread-2 time=1516242308672methodB begin threadName=Thread-3 time=1516242308672methodB end threadName=Thread-3 time=1516242313674
Use Condition to implement wait/notification
Public class MyService {private Lock lock = new ReentrantLock (); private Condition condition = lock. newCondition (); public void await () {try {lock. lock (); System. out. println ("await time is" + System. currentTimeMillis (); condition. await ();} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock () ;}} public void signal () {try {lock. lock (); System. out. println ("signal Time is" + System. currentTimeMillis (); condition. signal ();} finally {lock. unlock () ;}} public class Run {public static void main (String [] args) throws InterruptedException {MyService service = new MyService (); new Thread (() -> service. await ()). start (); Thread. sleep (3000); service. signal ();}}
View Code
Similarity:
1. Call lock. lock () before the conditional await method and signal method. Otherwise, an exception is thrown. Like wait and nofity, run the same command in synchronized code.
2. Object. wait () --> Condition. await (). Object. Policy () --> Condition. signal (), Object. policyall () --> Condition. signalAll ()
Advantages:
Multiple Condition instances can be created in a Lock object, and the thread object can be registered in the specified Condition, so that thread notification can be performed selectively, making scheduling more flexible.
Use multiple Condition to implement partial notification threads
Public class MyService {private Lock lock = new ReentrantLock (); private Condition conditionA = lock. newCondition (); private Condition conditionB = lock. newCondition (); public void awaitA () {try {lock. lock (); System. out. println ("begin awaitA time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName (); conditionA. await (); System. out. println ("end awaitA time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName ();} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock () ;}} public void awaitB () {try {lock. lock (); System. out. println ("begin awaitB time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName (); conditionB. await (); System. out. println ("end awaitB time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName ();} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock () ;}} public void signalAll_A () {try {lock. lock (); System. out. println ("signalAll_ B time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName (); conditionA. signalAll ();} finally {lock. unlock () ;}} public void signalAll_ B () {try {lock. lock (); System. out. println ("signalAll_ B time is" + System. currentTimeMillis () + "Thread name =" + Thread. currentThread (). getName (); conditionB. signalAll ();} finally {lock. unlock () ;}} public class Run {public static void main (String [] args) throws InterruptedException {MyService service = new MyService (); new Thread (() -> service. awaitA ()). start (); new Thread ()-> service. awaitB ()). start (); Thread. sleep (3000); service. signalAll_A ();}}
View Code
Test result: thread B is not awakened.
Begin awaitA time is 1516244219035 Thread name = Thread-0begin awaitB time is 1516244219036 Thread name = Thread-1signalAll_ B time is 1516244222035 Thread name = mainend awaitA time is 1516244222035 Thread name = Thread-0
Producers and consumers
Public class MyList {private Lock lock = new ReentrantLock (); private Condition condition = lock. newCondition (); private volatile List <String> list = new ArrayList <> (10); public void get () {try {System. out. println ("get, listSize =" + list. size (); lock. lock (); while (list. size () = 0) {System. out. println ("get wait, ThreadName =" + Thread. currentThread (). getName (); condition. await ();} System. out. println ("get-1"); list. remove (0); condition. signalAll ();} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock () ;}} public void set () {try {System. out. println ("set, listSize =" + list. size (); lock. lock (); while (list. size () = 10) {System. out. println ("set wait, ThreadName =" + Thread. currentThread (). getName (); condition. await ();} System. out. println ("set + 1"); list. add ("A"); condition. signalAll ();} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock () ;}} public class Run {public static void main (String [] args) throws InterruptedException {MyList consumer = new MyList (); for (int I = 0; I <10; I ++) {new Thread ()-> {while (true) {consumer. set ();}}). start (); new Thread ()-> {while (true) {consumer. get ();}}). start ();}}}
View CodeReentrantReadWriteLock
ReentrantLock has the effect of exclusive, that is, only one thread is executing the task after the ReentrantLock. lock () method at the same time. However, the efficiency is relatively low. Instead, the ReentrantReadWriteLock read/write lock can be used to improve the efficiency. The read/write lock has two locks. One is a read-related lock, also known as a shared lock, and the other is a write-related lock, also known as an exclusive lock. Only read locks are mutually exclusive, and others are mutually exclusive.
Example of non-mutex read locks
Public class Service {private ReentrantReadWriteLock lock = new ReentrantReadWriteLock (); public void read () {try {lock. readLock (). lock (); System. out. println ("Get read lock" + Thread. currentThread (). getName () + "" + System. currentTimeMillis (); Thread. sleep (10000);} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. readLock (). unlock () ;}} public class Run {public static void main (String [] args) throws InterruptedException {Service service Service = new Service (); new Thread (() -> service. read ()). start (); new Thread ()-> service. read ()). start ();}}
View Code
Test results: Read locks are obtained almost simultaneously, indicating they are not mutually exclusive.
Get read lock Thread-0 1516246020468 get read lock Thread-1 1516246020469
Examples of read/write mutex
Public class Service {private ReentrantReadWriteLock lock = new ReentrantReadWriteLock (); public void read () {try {lock. readLock (). lock (); System. out. println ("Get read lock" + Thread. currentThread (). getName () + "" + System. currentTimeMillis (); Thread. sleep (10000);} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. readLock (). unlock () ;}} public void write () {try {lock. writeLock (). lock (); System. out. println ("Get write lock" + Thread. currentThread (). getName () + "" + System. currentTimeMillis (); Thread. sleep (10000);} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. writeLock (). unlock () ;}} public class Run {public static void main (String [] args) throws InterruptedException {Service service Service = new Service (); new Thread (() -> service. read ()). start (); new Thread ()-> service. write ()). start ();}}
View Code
Test results: the write operation can be obtained only after the read lock is released.
Get read lock Thread-0 1516246209130 get write lock Thread-1 1516246219132