java除了使用关键字synchronized外,还可以使用ReentrantLock实现独占锁的功能。而且ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。这篇文章主要是从使用的角度来分析一下ReentrantLock。

ReentrantLock常常对比着synchronized来分析

ReentrantLock synchronized
独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。 独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。
可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。 可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;
可以响应中断 不可响应中断,一个线程获取不到锁就一直等待
可以实现公平锁机制 不可以实现公平锁机制

ps: 公平锁:在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

1、简单使用

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockTest {private static final Lock lock = new ReentrantLock();public static void main(String[] args) {initSimpleReentrantLockTest();}/*** 初始化并启动线程*/public static void initSimpleReentrantLockTest() {new Thread(ReentrantLockTest::simpleReentrantLockTest, "线程A").start();new Thread(ReentrantLockTest::simpleReentrantLockTest, "线程B").start();new Thread(ReentrantLockTest::simpleReentrantLockTest, "线程C").start();new Thread(ReentrantLockTest::simpleReentrantLockTest, "线程D").start();}/*** 测试锁的获取与释放*/public static void simpleReentrantLockTest() {try {lock.lock();System.out.println(Thread.currentThread().getName() + "\t获取了锁");TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + "\t释放了锁");lock.unlock();}}
}

执行结果,

线程A 获取了锁
线程A 释放了锁
线程B 获取了锁
线程B 释放了锁
线程C 获取了锁
线程C 释放了锁
线程D 获取了锁
线程D 释放了锁

2、ReentrantLock和synchronized不一样的地方, 实现公平锁

本次测试非公平锁,代码如下: 实现公平锁要在创建时进行声明 new ReentrantLock(true);
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockTest {private static final Lock lock = new ReentrantLock();public static void main(String[] args) {initFairLockReentrantLockTest();}/*** 初始化并启动线程*/public static void initFairLockReentrantLockTest() {new Thread(ReentrantLockTest::unFairLockReentrantLockTest, "线程A").start();new Thread(ReentrantLockTest::unFairLockReentrantLockTest, "线程B").start();new Thread(ReentrantLockTest::unFairLockReentrantLockTest, "线程C").start();new Thread(ReentrantLockTest::unFairLockReentrantLockTest, "线程D").start();}/*** 测试公平锁锁的获取与释放*/public static void unFairLockReentrantLockTest() {for (int i = 0; i < 2; i++) {try {lock.lock();System.out.println(Thread.currentThread().getName() + "\t获取了锁");TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + "\t释放了锁");lock.unlock();}}}
}
运行结果如下:

由于CPU切片问题,在释放锁后能够及时的再去获取锁,造成了释放锁后能够立刻获得锁

线程A 获取了锁
线程A 释放了锁
线程A 获取了锁
线程A 释放了锁
线程B 获取了锁
线程B 释放了锁
线程B 获取了锁
线程B 释放了锁
线程C 获取了锁
线程C 释放了锁
线程C 获取了锁
线程C 释放了锁
线程D 获取了锁
线程D 释放了锁
线程D 获取了锁
线程D 释放了锁

本次测试公平锁,测试公平锁,代码如下: 实现公平锁要在创建时进行声明 new ReentrantLock(true);
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockTest {private static final Lock lock = new ReentrantLock(true);public static void main(String[] args) {initFairLockReentrantLockTest();}/*** 初始化并启动线程*/public static void initFairLockReentrantLockTest() {new Thread(ReentrantLockTest::fairLockReentrantLockTest, "线程A").start();new Thread(ReentrantLockTest::fairLockReentrantLockTest, "线程B").start();new Thread(ReentrantLockTest::fairLockReentrantLockTest, "线程C").start();new Thread(ReentrantLockTest::fairLockReentrantLockTest, "线程D").start();}/*** 测试公平锁锁的获取与释放*/public static void fairLockReentrantLockTest() {for (int i = 0; i < 2; i++) {try {lock.lock();System.out.println(Thread.currentThread().getName() + "\t获取了锁");TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + "\t释放了锁");lock.unlock();}}}
}
运行结果如下:

由于增加公平锁,在释放锁后能够及时的再去获取锁也不能进行获取,获取锁的现状为顺序执行

线程A 获取了锁
线程A 释放了锁
线程B 获取了锁
线程B 释放了锁
线程C 获取了锁
线程C 释放了锁
线程D 获取了锁
线程D 释放了锁
线程A 获取了锁
线程A 释放了锁
线程B 获取了锁
线程B 释放了锁
线程C 获取了锁
线程C 释放了锁
线程D 获取了锁
线程D 释放了锁

3、测试响应中断

响应中断就是一个线程获取不到锁,不会傻傻的一直等下去,ReentrantLock会给予一个中断回应。在这里我们举一个死锁的案例。

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockTest {private static final Lock lock = new ReentrantLock();private static final Lock lock2 = new ReentrantLock();public static void main(String[] args) {initInterruptReentrantLockTest();}/*** 初始化响应中断并启动线程*/public static void initInterruptReentrantLockTest() {Thread threadA = new Thread(ReentrantLockTest::interruptReentrantLockTest, "线程A");Thread threadB = new Thread(ReentrantLockTest::interruptReentrantLockTest, "线程B");threadA.start();threadB.start();for (int i = 0; i < 5; i++) {try {TimeUnit.SECONDS.sleep(1);System.out.println("等待 "+(i+1)+" s");} catch (InterruptedException e) {e.printStackTrace();}}//中断结束A线程, B执行正常threadA.interrupt();}/*** 测试响应中断的锁的获取与释放*        让线程发生死锁*/public static void interruptReentrantLockTest() {String threadName = Thread.currentThread().getName();try {if (Objects.equals(threadName, "线程A")) {System.out.println(threadName + "\t开始获取lock!");lock.lockInterruptibly();System.out.println(threadName + "\t获取lock 开始等待获取lock2!");TimeUnit.SECONDS.sleep(1);lock2.lockInterruptibly();} else {System.out.println(threadName + "\t开始获取lock2!");lock2.lockInterruptibly();System.out.println(threadName + "\t获取lock2 开始等待获取lock!");TimeUnit.SECONDS.sleep(1);lock.lockInterruptibly();}} catch (InterruptedException e) {System.out.println(threadName + "\t异常!");e.printStackTrace();} finally {lock.unlock();lock2.unlock();System.out.println(threadName + "\t获取到了资源,正常结束!");}}
}
执行结果

线程A 开始获取lock!
线程B 开始获取lock2!
线程A 获取lock 开始等待获取lock2!
线程B 获取lock2 开始等待获取lock!
等待 1 s
等待 2 s
等待 3 s
等待 4 s
等待 5 s
线程A 异常!
线程B 获取到了资源,正常结束!
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at self.studycode.lock.ReentrantLockTest.interruptReentrantLockTest(ReentrantLockTest.java:103)
at java.lang.Thread.run(Thread.java:748)
Exception in thread “线程A” java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at self.studycode.lock.ReentrantLockTest.interruptReentrantLockTest(ReentrantLockTest.java:116)
at java.lang.Thread.run(Thread.java:748)

ReentrantLock可重入锁的使用相关推荐

  1. java condition_(原创)Java的ReentrantLock(可重入锁)下的Condition

    先来看一下这个Condition的使用场景,在LinkedBlockingQueue(链表的阻塞队列)类中包含如下的定义,通过使用lock.newCondition()方法,可以获得一个Conditi ...

  2. 聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁

    这篇讲讲ReentrantLock可重入锁,JUC里提供的可重入锁是基于AQS实现的阻塞式可重入锁.这篇 聊聊高并发(十六)实现一个简单的可重入锁 模拟了可重入锁的实现.可重入锁的特点是: 1. 是互 ...

  3. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  4. Java并发编程-ReentrantLock可重入锁

    目录 1.ReentrantLock可重入锁概述 2.可重入 3.可打断 4.锁超时 5.公平锁 6.条件变量 Condition 1.ReentrantLock可重入锁概述 相对于 synchron ...

  5. 6※、线程同步、同步锁、同步代码块的使用、同步锁释放的时机、ReentrantLock可重入锁、公平锁与非公平锁的区别、什么是死锁、线程间的通信(生产者和消费者模式)

    线程锁 1.※线程的同步:(要确保对象锁是一致的) 1.未使用同步锁的抢票 2.使用了同步锁的抢票 3.线程-同步代码块的使用 4.同步方法和代码块的区别 5.同步锁释放的时机 练习:多线程生产手机 ...

  6. 1、Lock接口以及ReentrantLock可重入锁

    1.序 文章目录 1.序 2.Lock 接口 3.AbstractQueuedSynchronizer 3.1 双端队列 3.2 state变量 4.ReentrantLock简介以及其非公平锁模式 ...

  7. 【并发编程】线程锁--Synchronized、ReentrantLock(可重入锁)

    在说锁之前,我们要明白为什么要加锁,不加锁会怎样? 在并发编程中,很容易出现线程安全问题,接下来我们看个很经典的例子--银行取钱,来看一下有关线程安全的问题. 取钱的流程可以分为一下几个步骤: 1.用 ...

  8. Java ReentrantLock可重入锁的源码深度解析

    Java的ReentrantLock的源码实现,包括加锁.解锁的源码,以及公平性.重入性的实现! 文章目录 1 ReentrantLock的概述 1.1 ReentrantLock的API方法 1.2 ...

  9. 并发类编程—ReentrantLock(可重入锁)

    1.概念 ReentantLock继承接口 Lock 并实现了接口中定义的方法,他是一种可重入锁,除了能完成synchronized 所能完成的所有工作外,还提供了中断锁.定时锁等避免多线程死锁的方法 ...

  10. ReentrantLock可重入锁的使用场景(转)

    摘要 从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些. 场景1:如果发现该操作已经在执行中则不再执行(有状态执行) a.用在定时任务时,如果任务执行时间可能超过下次 ...

最新文章

  1. python网站开发linux_使用Python编写Linux系统守护进程实例
  2. c++以代理的方式来实现接口化编程
  3. 50个Web设计师超便利的工具
  4. 2016 hctf fheap 题解
  5. Linux技术进阶示意图
  6. JAVA NP插件,特定的宽度600,插件就不显示
  7. autosar架构详细介绍_干货|非常详细的 Ceph 介绍、原理、架构
  8. 开博第一篇:一个关于正则表达式相关的问题
  9. 微软服务器补丁每月几号发布,微软11月安全公告 发布一个紧急级补丁
  10. 软件工程导论01-概论
  11. css颜色和长度简写
  12. 罗克韦尔AB PLC ControlLogix PLC的介绍和选型
  13. 什么是IO流?什么是IO流?
  14. Tomcat部署与优化
  15. 删除Mac版QQ聊天记录
  16. SWF Decompiler/Parser/Creater Comparison(opensource)
  17. python高德 查询县_Python获取高德地图省市区县列表
  18. Python基于密度的聚类
  19. 东方木网吧上网遇到难题:网吧浏览器总是自动刷新
  20. python实现DSA签名数字证书

热门文章

  1. .net core 与ELK(4)后台运行els可视化工具和Kibana
  2. sphinx 全文检索 笔记一
  3. tensorflow构建CNN模型时的常用接口函数
  4. Educational Codeforces Round 45 (Rated for Div. 2) G - GCD Counting
  5. javascript探秘-检测浏览器和操作系统
  6. OBIEE-----ClusterControler通信的问题
  7. c#窗体单机版家庭消费系统事例(附:源码下载)
  8. 大学计算机课程复习--软件工程
  9. 思科路由器RIP路由汇总
  10. HCIP-RS-GRE