2019独角兽企业重金招聘Python工程师标准>>>

重入锁(ReentrantLock)

  ReentrantLock是一种可重入的互斥锁,并且加锁是一种显式操作,对逻辑控制的灵活性远远大于synchronized关键字。重入锁是可以完全替代synchronized。并且重入锁的性能是远高于synchronized的,但是jdk6.0开始,jdk对synchronized做了大量的优化,使得两者性能差距不大。另外,ReentrantLock可结合Condition、以及提供了中断响应、锁申请等待限时、公平锁等。

公平锁、非公平锁(ReentrantLock)

  ReentrantLock分为“公平锁”和“非公平锁”。它们的区别体现在获取锁的机制上是否公平。在“公平锁”的机制下,线程依次排队获取锁;而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。

 运行如下代码,对比公平锁和非公平锁的运行结果

    public static void main(String[] args) throws InterruptedException {Lock noFairReentrantLock = new ReentrantLock();Lock fairReentrantLock = new ReentrantLock(true);Thread[] threads = new Thread[10];for(int i=0;i<10;i++){threads[i] = new Thread(()->{System.out.println(Thread.currentThread().getName()+"  [start]");fairReentrantLock.lock();//也可以切换为非公平锁,观察运行结果try {System.out.println(Thread.currentThread().getName()+"  [获得锁]");}finally {fairReentrantLock.unlock();}});}for(int i=0;i<5;i++){threads[i].start();}for(int i=0;i<5;i++){threads[i].join();}}}

重入锁的中断响应功能

对于synchronized块来说,要么获取到锁执行,要么持续等待。而重入锁的中断响应功能就合理地避免了这样的情况。比如,一个正在等待获取锁的线程被“告知”无须继续等待下去,就可以停止工作了。

下面我们看一个利用中断响应功能解决的一个死锁问题

public static void main(String[] args) throws InterruptedException {ReentrantLock lock1 = new ReentrantLock();ReentrantLock lock2 = new ReentrantLock();//线程t1和t2构成了死锁,此时我们可以中断的方式解决死锁问题Runnable runnable = ()->{try {if(Thread.currentThread().getName().equals("t1")){lock1.lockInterruptibly(); //在加锁的过程中仍然可以相应中断Thread.sleep(100);lock2.lockInterruptibly();}else{lock2.lockInterruptibly();Thread.sleep(100);lock1.lockInterruptibly();}} catch (InterruptedException e) {e.printStackTrace();}finally {if (lock1.isHeldByCurrentThread()) lock1.unlock();if (lock2.isHeldByCurrentThread()) lock2.unlock();}};Thread t1 = new Thread(runnable,"t1");Thread t2 = new Thread(runnable,"t2");t1.start();t2.start();Thread.sleep(1000);//以中断的方式解决死锁问题t2.interrupt();}

锁申请等待限时

可以使用 tryLock()或者tryLock(long timeout, TimeUtil unit) 方法进行一次限时的锁等待。

  • tryLock(),线程尝试获取锁,如果获取到锁则继续执行,如果锁被其他线程持有,则立即返回false,也就是不会使当前线程等待,所以不会产生死锁。
  • tryLock(long timeout, TimeUtil unit),表示在指定时长内获取到锁则继续执行,如果等待指定时长后还没有获取到锁则返回false。
public static void main(String[] args) throws InterruptedException {ReentrantLock lock = new ReentrantLock();Runnable runnable = ()->{try {if (lock.tryLock(1, TimeUnit.SECONDS)) { // 等待1秒Thread.sleep(2000);} else {System.err.println(Thread.currentThread().getName() + "获取锁失败!");}} catch (Exception e) {if (lock.isHeldByCurrentThread()) lock.unlock();}};Thread t1 = new Thread(runnable,"t1");Thread t2 = new Thread(runnable,"t2");t1.start();t2.start();}

ReentrantLock 配合 Condition 使用

配合关键字synchronized使用的方法如:await()、notify()、notifyAll(),同样配合ReentrantLock 使用的Conditon提供了以下方法:

public interface Condition {void await() throws InterruptedException; // 类似于Object.wait()void awaitUninterruptibly(); // 与await()相同,但不会再等待过程中响应中断long awaitNanos(long nanosTimeout) throws InterruptedException;boolean await(long time, TimeUnit unit) throws InterruptedException;boolean awaitUntil(Date deadline) throws InterruptedException;void signal(); // 类似于Obejct.notify()void signalAll();
}

ReentrantLock 配合 Condition的例子

public static void main(String[] args) throws InterruptedException {ReentrantLock lock = new ReentrantLock(true);Condition condition = lock.newCondition();Thread t = new Thread(()->{try {lock.lock();System.err.println(Thread.currentThread().getName() + "-线程开始等待...");condition.await();System.err.println(Thread.currentThread().getName() + "-线程继续进行了");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}, "t1");t.start();Thread.sleep(1000);System.err.println("过了1秒后...");lock.lock();condition.signal(); // 调用该方法前需要获取到创建该对象的锁否则会产生java.lang.IllegalMonitorStateException异常lock.unlock();}

ReentrantLock函数列表

// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()
// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)
// 查询当前线程保持此锁的次数。
int getHoldCount()
// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()
// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正等待获取此锁的线程估计数。
int getQueueLength()
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)
// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)
// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()
// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)
// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()
// 查询此锁是否由任意线程保持。
boolean isLocked()
// 获取锁。
void lock()
// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()
// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()
// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()
// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)
// 试图释放此锁。
void unlock()

转载于:https://my.oschina.net/cqqcqqok/blog/1944196

JUC锁框架——重入锁ReentrantLock相关推荐

  1. 年轻人,看看 Redisson 分布式锁—可重入锁吧!太重要了

    作者 | 李祥    责编 | 张文 来源 | 企鹅杏仁技术站(ID:xingren-tech) 引言 作为后端开发,对于所谓的线程安全.高并发等一系列名词肯定都不会陌生,相关的一些概念及技术框架是面 ...

  2. Juc07_乐观锁和悲观锁、公平锁和非公平锁、递归锁(可重入锁)、死锁及排查、自旋锁

    文章目录 ①. 乐观锁和悲观锁 ②. 公平锁和非公平锁 ③. 可重入锁(又名递归锁) ④. 死锁及排查 ⑥. 自旋锁 ①. 乐观锁和悲观锁 ①. 悲观锁(synchronized关键字和Lock的实现 ...

  3. 年轻人,看看Redisson分布式锁—可重入锁吧!太重要了

    1.引言 作为后端开发,对于所谓的线程安全.高并发等一系列名词肯定都不会陌生,相关的一些概念及技术框架是面试中的宠儿,也是工作中解决一些特定场景下的技术问题的银弹.今天我们就来聊聊这些银弹中的其中一枚 ...

  4. 谈谈java并发锁(重入锁、读写锁、公平锁)

    目录 重入锁 简单重入锁 重入锁的等待通知(Condition) 多Condition 公平锁和非公平锁 读写锁ReentrantReadWriteLock 锁优化总结: 重入锁和读写锁,他们具有比s ...

  5. 可重入锁 不可重入锁_什么是可重入锁?

    可重入锁 不可重入锁 在Java 5.0中,增加了一个新功能以增强内部锁定功能,称为可重入锁定. 在此之前,"同步"和"易失性"是实现并发的手段. public ...

  6. 测试Lock锁-可重入锁(Java)

    测试Lock锁-可重入锁(Java) package src.thread;import java.util.concurrent.locks.ReentrantLock;public class T ...

  7. 可重入锁/不可重入锁,公平锁/非公平锁,乐观锁/悲观锁,独享锁/共享锁,偏向锁/轻量级锁/重量级锁,分段锁,自旋锁

    在并发编程中,会涉及到各种各样的锁,这篇文章主要介绍各种锁的分类以及作用. 介绍的内容如下: 可重入锁/不可重入锁 公平锁/非公平锁 乐观锁/悲观锁 独享锁/共享锁 偏向锁/轻量级锁/重量级锁 分段锁 ...

  8. 第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁【Java面试题】

    第二季:5值传递和引用传递[Java面试题] 前言 推荐 值传递 说明 题目 24 TransferValue醒脑小练习 第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自 ...

  9. RocketMQ的broker处理消息commit时,加锁应该使用自旋锁还是重入锁

    讨论的主题 以下内容基于rocketmq4.7.1版本,并且集群模型采用的是DLedger 2主4从,主从节点在不同的机架上,所以关于其中提到的压测数据请勿直接套用自己的环境,仅供参考. rocket ...

  10. Java 可重入锁 不可重入锁

    文章目录 Java 可重入锁 & 不可重入锁 概述 论证synchronized是可重入锁: 论证Lock是可重入锁: 自定义不可重入锁: Java 可重入锁 & 不可重入锁 概述 可 ...

最新文章

  1. 英雄传说服务器维护中,英雄传说:星之轨迹 正统《轨迹》手游无法连接服务器是什么原因...
  2. mongodb 安装启动
  3. 无向图强联通分量-洛谷 P2860 [USACO06JAN]冗余路径Redundant Paths
  4. 源码与tarball套件管理程序笔记摘录
  5. json格式的字符串序列化和反序列化的一些高级用法
  6. python3图片转代码_python3图片转换二进制存入mysql示例代码
  7. 轻松搞定 Nginx 配置代码的神器!
  8. QML笔记-键盘事件中同时响应onDigitXXPressed与onPressed
  9. idea java jni 调试_使用 IntelliJ IDEA 和 IntelliJ Clion 进行 JNI 开发
  10. NetCDF文件介绍
  11. 前端系列教程之JS(自认为有用代码)
  12. Ant Design Upload 文件上传功能
  13. 广州三本找Java实习经历
  14. 论文写作课程收获总结
  15. dede织梦网站源码安装教程
  16. No387FirstUniqueCharacterInAString
  17. Linux 两台主机之间建立信任关系方式及基本原理
  18. 年份必须是4位数 C语言,输入年份(四位数),判断是否是闰年 C语言编程
  19. pytorch转onnx踩坑日记
  20. 卓音工作室2022讨论班第五期——JavaScript基础

热门文章

  1. Linux系统磁盘分区、删除分区、格式化、挂载、卸载、开机自动挂载的方法总结...
  2. JavaScript必须了解的知识点总结【转】
  3. Linux部署之批量自动安装系统之测试篇
  4. 123 Python程序中的线程操作-协程
  5. 一本通1598【 例 2】最大连续和
  6. vue开发中v-for在Eslint的规则检查下出现:Elements in iteration expect to have 'v-bind:key' directives...
  7. 剑指offer【书】之简历抒写
  8. Python网络编程笔记二
  9. IFTT-意大利金融交易税
  10. Elasticsearch从0.90(0.90.x)到1.2(1.x)API的变化-二