in multithreaded operation. Guarantees the atomicity of a shared resource. The first thing that comes to mind is to use the synchronized keyword
Provide a more flexible and powerful ReentrantLock in jdk5
Use reentrantLock.lock(); to acquire the lock Use reentrantLock.unlock(); to release the lock
public class ReentrantLockTest { ReentrantLock reentrantLock = new ReentrantLock(); public void add(Object data) throws InterruptedException { try { reentrantLock.lock(); System.out.println( "Simulation add time" ); Thread.sleep(2000); System.out.println( "Adding completed" ); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public void get() throws InterruptedException { try { reentrantLock.lock(); System.out.println( "Simulate acquisition" ); Thread.sleep(1000); System.out.println( "Adding completed" ); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public static void main(String[] args) { final ReentrantLockTest reentrantLockTest=new ReentrantLockTest(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLockTest.add(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLockTest.get(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start();; }
The difference between synchronized and ReentrantLock
1.synchronized is handed over to the jvm to schedule. ReentrantLock is controlled by java code
2. Synchronized will greatly reduce performance when many threads compete. ReentrantLock will not compete with many threads.
3.ReentrantLock must cooperate with finally, otherwise it is easy to cause deadlock
4.synchronized can only be synchronized in a method block. ReentrantLock can span methods
ReentrantLock reentrantLock = new ReentrantLock(); public void Test1() { reentrantLock.lock(); /* * execute logic */ Test2 (); } public void Test2 () { reentrantLock.unlock(); }
5. ReentrantLock can perform fair lock selection
When to choose ReentrantLock
1. A thread needs to interrupt tryLock while waiting for control of a lock
public class ReentrantLockTest { ReentrantLock reentrantLock = new ReentrantLock(); public void add(Object data) throws InterruptedException { try { reentrantLock.lock(); Thread.sleep(10000); System.out.println( "Simulation add time" ); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public void get() throws InterruptedException { try { reentrantLock.tryLock( 1000, TimeUnit.MILLISECONDS); // Try to acquire the lock for 1000 milliseconds and fail to give up System.out.println("simulated acquisition" ); Thread.sleep(1000); System.out.println( "Get complete" ); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public static void main(String[] args) { final ReentrantLockTest reentrantLockTest=new ReentrantLockTest(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLockTest.add(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLockTest.get(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println( "Execute other business logic" ); } },"t2").start();; } }
The first thread acquires the lock and waits 5 seconds. When reentrantLock.tryLock(1000, TimeUnit.MILLISECONDS) will try to acquire the lock, if not acquired within 1 second, throw an exception and continue to execute
Simulate acquisition Acquired Exception in thread "t2" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source) at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source) at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source) at com.bjsxt.height.concurrent019.ReentrantLockTest.get(ReentrantLockTest.java:32) at com.bjsxt.height.concurrent019.ReentrantLockTest$2.run(ReentrantLockTest.java:56) at java.lang.Thread.run(Unknown Source) Simulation of new time-consuming
2. Some wait-notify needs to be handled separately. The Condition application in ReentrantLock can control which thread to notify
public static void main(String[] args) throws InterruptedException { final ReentrantLock reentrantLock = new ReentrantLock(); final Condition condition1= reentrantLock.newCondition(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLock.lock(); condition1.await(); System.out.println( "Thread 1 executes down" ); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { reentrantLock.unlock(); } } }).start(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { reentrantLock.lock(); Thread.sleep(5000); condition1.signal(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { reentrantLock.unlock(); } } },"t2").start(); Thread.sleep( 2000 ); // Cancel condition1 waiting }
reentrantLock.newCondition() can be multiple new. All waiting conditions can be awakened by reentrantLock.signalAll()
3. With fair lock function, each incoming thread will wait in line
ReentrantLock reentrantLock = new ReentrantLock(true) is fair