ReentrantLock(排他锁)
ReentrantLock源码
https://www.cnblogs.com/LQBlog/p/15206866.html
简单demo
在多线程操作时。保证一块共享资源的原子性。第一想到的就是用synchronized关键字
在jdk5提供一个更灵活更强大的 ReentrantLock
使用reentrantLock.lock();获得锁 使用reentrantLock.unlock();释放锁
public class ReentrantLockTest { ReentrantLock reentrantLock = new ReentrantLock(); public void add(Object data) throws InterruptedException { try { reentrantLock.lock(); System.out.println("模拟新增耗时"); Thread.sleep(2000); System.out.println("新增完毕"); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public void get() throws InterruptedException { try { reentrantLock.lock(); System.out.println("模拟获取"); Thread.sleep(1000); System.out.println("新增完毕"); } 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();; }
synchronized与ReentrantLock区别
1.synchronized是交给jvm来调度的。ReentrantLock是通过java代码控制的
2.在synchronized在很多线程竞争的时候会使性能大大下降ReentrantLock在很多线程竞争是不会
3.ReentrantLock必须配合finally 否则容易产生死锁
ReentrantLock reentrantLock = new ReentrantLock(); public void Test1() { reentrantLock.lock(); /* * 执行逻辑 */ Test2(); } public void Test2() { reentrantLock.unlock(); }
5.ReentrantLock可以进行公平锁选择
什么情况下选用ReentrantLock
1.某个线程在等待一个锁的控制权的这段时间需要中断 tryLock
public class ReentrantLockTest { ReentrantLock reentrantLock = new ReentrantLock(); public void add(Object data) throws InterruptedException { try { reentrantLock.lock(); Thread.sleep(10000); System.out.println("模拟新增耗时"); } finally { // TODO: handle finally clause reentrantLock.unlock(); } } public void get() throws InterruptedException { try { reentrantLock.tryLock(1000, TimeUnit.MILLISECONDS);//尝试获得锁1000毫秒 获取不到放弃 System.out.println("模拟获取"); Thread.sleep(1000); System.out.println("获取完毕"); } 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("执行其他业务逻辑"); } },"t2").start();; } }
第一个线程获取锁 等待5秒。当reentrantLock.tryLock(1000, TimeUnit.MILLISECONDS) 会尝试获得锁 若果1秒之内没获取 抛出异常 继续往下执行
打印
模拟获取 获取完毕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) 模拟新增耗时
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制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("线程1往下执行"); } 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); //取消 condition1等待 }
reentrantLock.newCondition()可以new多个 。可以通过reentrantLock.signalAll()唤醒所有等待的condition
3.具有公平锁功能,每个到来的线程都将排队等候
ReentrantLock reentrantLock = new ReentrantLock(true) 则为公平锁
ReentrantLock与synchronized区别
1.从底层实现synchronized是JVM层面的,Reentrantlock是应用层面
2.synchronized是通过jvm 的monitor指令实现加锁和释放锁,Reentrantlock是在应用上基于AQS实现+CAS实现
3.synchronized能够保证线程的原子性、可见性、有序性、可重入性。Reentrantlock只能保证 原子性,和可重入性。如果需要保证可见性需要加volatile关键字。
4.在jdk1.6之前Reentrantlock的性能优于synchronized,因为synchronized全部都是重量级锁 直接参与竞争,在jdk1.6之后进行了优化通过锁升级(偏向锁 轻量级锁 重量级锁)锁粗化 锁消除 的优化方式,锁升级 本质在以前mointor锁直接参与竞争获取 优化前面增加应用层面的CAS判断 减少直接参与竞争
5.jdk1.6之后更推荐使用synchronized