reentrantlock_lock condition

reentrantlock_lock conditionReentrantLock锁的底层实现已经阐述过了,那么如何使用,本文进行下样例展示,主要说两个功能:1.lock及中断,2.申请等待时间;lock锁/***@Description:*@author:Erick*@version:1.0*@time:2018-9-25*/publicclassReentrantLockThreadimple…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

ReentrantLock锁的底层实现已经阐述过了,那么如何使用,本文进行下样例展示,主要说3个:1. lock及中断,2. 申请等待时间,3、公平锁

lock锁

/** * @Description : * @author : Erick * @version : 1.0 * @time :2018-9-25 */ public class ReentrantLockThread implements Runnable{ 
     private static ReentrantLock reentrantLock = new ReentrantLock(); private int i = 0; public void run() { 
     for (int j = 0; j < 10; j++) { 
     //上锁 reentrantLock.lock(); try { 
     i++; System.out.println("当前线程"+Thread.currentThread().getName()+"输出 i :" + i); } finally { 
     //释放锁 reentrantLock.unlock(); } } } } 

上例中一个实现一个线程,并定义ReentrantLock,与synchronized不同的是要显示的lock上锁并手动释放锁,是一套缺一不可,将上锁和释放锁注释然后调用会出现线程交替执行的情况,我们写个测试类

/** * @Description : * @author : Erick * @version : 1.0 * @time :2018-9-25 */ public class ReentrantLockTest { 
     public static void main(String[] args) { 
     //定义两个线程 ReentrantLockThread reentrantLockThread1 = new ReentrantLockThread(); ReentrantLockThread reentrantLockThread2 = new ReentrantLockThread(); //调用run方法执行其实就是调用的接口方法,主线程运行在打印线程名称时都是main, //而使用Thread.start()则是新起一个线程进行调用,更新执行标识 // reentrantLockThread1.run(); // reentrantLockThread2.run(); Thread thread1 = new Thread(reentrantLockThread1); Thread thread2 = new Thread(reentrantLockThread2); thread1.start(); thread2.start(); } } 

为方便展示只循环了10次注释掉上锁和释放锁的代码,执行结果为:

当前线程Thread-0输出 i :1 当前线程Thread-1输出 i :1 当前线程Thread-0输出 i :2 当前线程Thread-1输出 i :2 当前线程Thread-0输出 i :3 当前线程Thread-1输出 i :3 当前线程Thread-0输出 i :4 当前线程Thread-1输出 i :4 当前线程Thread-0输出 i :5 当前线程Thread-1输出 i :5 当前线程Thread-0输出 i :6 当前线程Thread-1输出 i :6 当前线程Thread-0输出 i :7 当前线程Thread-1输出 i :7 当前线程Thread-0输出 i :8 当前线程Thread-1输出 i :8 当前线程Thread-1输出 i :9 当前线程Thread-0输出 i :9 当前线程Thread-1输出 i :10 当前线程Thread-0输出 i :10 

若加上锁,则是一个先执行完另外一个再执行,获取到锁后,第二个线程在请求时发现锁被占用则加入到队列中等待,所以等第一个线程执行完成后,第二个线程才会执行,执行结果如下:

当前线程Thread-0输出 i :1 当前线程Thread-0输出 i :2 当前线程Thread-0输出 i :3 当前线程Thread-0输出 i :4 当前线程Thread-0输出 i :5 当前线程Thread-0输出 i :6 当前线程Thread-0输出 i :7 当前线程Thread-0输出 i :8 当前线程Thread-0输出 i :9 当前线程Thread-0输出 i :10 当前线程Thread-1输出 i :1 当前线程Thread-1输出 i :2 当前线程Thread-1输出 i :3 当前线程Thread-1输出 i :4 当前线程Thread-1输出 i :5 当前线程Thread-1输出 i :6 当前线程Thread-1输出 i :7 当前线程Thread-1输出 i :8 当前线程Thread-1输出 i :9 当前线程Thread-1输出 i :10 

中断

中断是两个线程分表获取对方需要的数据时即死锁,为了防止线程一直等待浪费资源,ReentrantLock提供了中断响应接口支持,及可以手动调用线程中断来强制让一个线程中断并返回异常信息,而另外一个线程则会拿到锁继续执行。

/** * @Description :中断响应 * @author : Erick * @time :2018-9-25 */ public class ReentrantLockInterrupt implements Runnable{ 
     /** * 定义两个锁,模拟响应中断 */ private static ReentrantLock reentrantLock1 = new ReentrantLock(); private static ReentrantLock reentrantLock2 = new ReentrantLock(); /** * 增加一个标识表名哪个设置中断响应所 */ private String lockFlag; public ReentrantLockInterrupt(String lockFlag) { 
     this.lockFlag = lockFlag; } public void run() { 
     try { 
     //lockFlag = 1则先设置reentrantLock1中断锁 //否则reentrantLock2 设置中断锁 if ("1".equals(lockFlag)){ 
     reentrantLock1.lockInterruptibly(); Thread.sleep(500); reentrantLock2.lockInterruptibly(); System.out.println("reentrantLock1执行"); }else { 
     reentrantLock2.lockInterruptibly(); Thread.sleep(500); reentrantLock1.lockInterruptibly(); System.out.println("reentrantLock2执行"); } } catch (InterruptedException e) { 
     e.printStackTrace(); } finally { 
     //要下判断是否获取当前线程的锁,若是则释放掉 if (reentrantLock1.isHeldByCurrentThread()){ 
     reentrantLock1.unlock(); System.out.printf("释放当前锁reentrantLock1"); } if (reentrantLock2.isHeldByCurrentThread()){ 
     reentrantLock2.unlock(); System.out.println("释放当前锁reentrantLock2"); } } } } 

上例再执行是会出现死锁现象,因两个线程一个走if一个走else,都会拿到对方需要的锁谁都不会释放,直到一个线程中断另一个才会执行。

/** * @Description : * @author : Erick * @time :2018-9-25 */ public class ReentrantLockInterruptTest { 
     public static void main(String[] args) throws InterruptedException { 
     ReentrantLockInterrupt reentrantLockInterrupt1 = new ReentrantLockInterrupt("1"); ReentrantLockInterrupt reentrantLockInterrupt2 = new ReentrantLockInterrupt("2"); //这里新定义两个线程Thread为了使用interrupt方法对线程进行中断 Thread thread1 = new Thread(reentrantLockInterrupt1); Thread thread2 = new Thread(reentrantLockInterrupt2); thread1.start(); thread2.start(); Thread.sleep(1000); thread2.interrupt(); } } 

测试用例中thread1请求if,thread2请求else,启动两个线程同时获取锁出现死锁,然后再休眠1s,确保都拿到锁了方便演示,执行情况如下:

释放当前锁reentrantLock2 java.lang.InterruptedException reentrantLock1执行 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 com.erick.study.reentrantlock.thread.ReentrantLockInterrupt.run(ReentrantLockInterrupt.java:41) at java.lang.Thread.run(Thread.java:745) 释放当前锁reentrantLock1释放当前锁reentrantLock2 

线程2被中断抛出异常,线程1拿到锁可以顺利执行。

等待锁tryLock

有两种方式:1、无参即尝试获取锁获取不到则直接返回,2、设置等待时间超过时间后还是无法获取到则返回,否则获取锁执行。

/** * @author : Erick * @version : 1.0 * @Description : * @time :2018-9-30 */ public class ReentrantLockTryLock implements Runnable{ 
     private ReentrantLock reentrantLock = new ReentrantLock(); private int i = 0; public void run() { 
     for (int j = 0; j < 10; j++) { 
     try { 
     //设置等待时间为1秒 if (reentrantLock.tryLock(1,TimeUnit.SECONDS)){ 
     i++; System.out.println(Thread.currentThread().getName()+"当前值:"+i); //设置休眠时间 Thread.sleep(500); }else { 
     System.out.println(Thread.currentThread().getName()+"无法获取锁"); } } catch (Exception e) { 
     e.printStackTrace(); System.out.printf("异常"+e.getMessage()); } finally { 
     if (reentrantLock.isHeldByCurrentThread()){ 
     reentrantLock.unlock(); } } } } } 

tryLock不设置等待时间,执行都能获取到锁交替运行,而加上等待时间后会等待一段时间若还是获取不到锁则打印无法获取锁,测试类

/** * @author : Erick * @version : 1.0 * @Description : * @time :2018-9-30 */ public class ReetrantLockTryLockTest { 
     public static void main(String[] args) { 
     ReentrantLockTryLock reentrantLockTryLock = new ReentrantLockTryLock(); Thread thread1 = new Thread(reentrantLockTryLock); Thread thread2 = new Thread(reentrantLockTryLock); thread1.setName("thread1"); thread2.setName("thread2"); thread1.start(); thread2.start(); } } 

公平锁

公平锁是按照进入队列的先后顺序执行的,因为Demo比较简单,每次执行的结果也不一样。

/** * @author : Erick * @version : 1.0 * @Description : * @time :2018-9-30 */ public class ReentrantLockFair implements Runnable{ 
     //实例化指定公平锁方式 private ReentrantLock reentrantLock = new ReentrantLock(true); public void run() { 
     for (int j = 0; j < 10000; j++) { 
     try { 
     reentrantLock.lock(); System.out.println(Thread.currentThread().getName()+"获取锁"); } catch (Exception e) { 
     e.printStackTrace(); } finally { 
     reentrantLock.unlock(); } } } } 

比较简单获取锁,然后输出运行的线程名称,测试类

/** * @author : Erick * @version : 1.0 * @Description : * @time :2018-9-30 */ public class ReentrantLockFairTest { 
     public static void main(String[] args) { 
     ReentrantLockFair reentrantLockFair = new ReentrantLockFair(); Thread thread1 = new Thread(reentrantLockFair); Thread thread2 = new Thread(reentrantLockFair); thread1.start(); thread2.start(); } } 

执行结果,粘贴部分结果

Thread-0获取锁 Thread-0获取锁 Thread-0获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 Thread-0获取锁 Thread-1获取锁 

以上是整理的关于重入锁ReentrantLock的几个简单的Demo,如有不妥之处也请指正。
源代码可以从GitHub或者码云上下载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183277.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月11日 上午8:46
下一篇 2022年10月11日 上午8:46


相关推荐

  • 蓝桥杯题目 计算后续日期

    蓝桥杯题目 计算后续日期蓝桥杯题目计算后续日期题目描述我们经常要计算 从今天往后 N 天之后是哪一天 哪年哪月哪日 现在我们就可以编写一个程序 推算指定日期之后的第 N 天是什么日期 输入输入有多组 每组测试用例有一行 包括四个整数 分别表示年 月 日和第 N 天 输出对于每组测试用例 输入由一行组成 表示 年月日 N 天后的 的年 月 日样例输入样例输出 2012

    2025年8月24日
    7
  • 电阻电容电感的常用标注方法(手机电容和电阻的区分)

    认识电容及电容电阻的标注   一、认识电容及电容的标注①电容的功能和表示方法。由两个金属极,中间夹有绝缘介质构成。电容的特性主要是隔直流通交流,因此多用于级间耦合、滤波、去耦、旁路及信号调谐。电容在电路中用“C”加数字表示,比如C8,表示在电路中编号为8的电容。②电容的分类。电容按介质不同分为:气体介质电容,液体介质电容,无机固体介质电容,有机固体介质电容电解电容。按极性分为:有极性电容和无极性电

    2022年4月12日
    140
  • C++游戏编程(一开篇)

    C++游戏编程(一开篇)

    2021年12月3日
    64
  • spss之单因素方差分析因子不显示_无重复单因素方差分析

    spss之单因素方差分析因子不显示_无重复单因素方差分析方差分析方差分析又称F检验,在实际应用中常常需要对多个整体的均值进行比较,并分析他们之间是否存在差异,差异是否显著,这个时候我们就需要使用方差分析。方差分析用于研究自变量和因变量之间是否有关系及其关系强度的一种分析方法。其实质是将所有测量值之间方差分析的三个概念1.因素:2….

    2026年4月13日
    4
  • mysql wal_什么是 WAL

    mysql wal_什么是 WAL什么是 WALWAL WriteAheadLo 预写日志 是数据库系统中常见的一种手段 用于保证数据操作的原子性和持久性 在计算机科学中 预写式日志 Write aheadlogging 缩写 WAL 是关系数据库系统中用于提供原子性和持久性 ACID 属性中的两个 的一系列技术 在使用 WAL 的系统中 所有的修改在提交之前都要先写入 log 文件中 log 文件中通常包括 redo

    2026年3月18日
    2
  • webstorm 使用git_idea使用maven创建web项目

    webstorm 使用git_idea使用maven创建web项目JS开发神器WebStorm的使用,包括Git的配置、文件提交至Git、文件名详解等。

    2025年10月11日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号