ReentrantLock介绍

文章目录

    • ReentrantLock
      • 1、构造函数
      • 2、公平性锁和非公平性锁
        • (1)公平性锁和非公平性锁示例
        • (2)公平锁和非公平锁的实现
          • 公平性锁:FairLock
          • 非公平性锁
        • (3)Condition
          • 生产者和消费者
        • 循环打印ABC

ReentrantLock

ReentantLock是java中重入锁的实现,一次只能有一个线程来持有锁,包含三个内部类,SyncNonFairSyncFairSync

1、构造函数

无参构造,默认使用的是非公平性锁

public ReentrantLock() {sync = new NonfairSync();}

有参构造, Boolean类型的参数 true:表示公平性锁 false:非公平性锁

    public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}

reentantlock是lock接口的实现类,即实现了Lock接口下所有的方法;
获取锁的方法lock、trylock、lockintertuptibly加锁方式以及释放锁方法

2、公平性锁和非公平性锁

(1)公平性锁和非公平性锁示例

NonFairAndFairDemo类

import java.util.concurrent.locks.ReentrantLock;public class NonFairAndFairDemo implements Runnable {//静态变量(线程共享)private static int num = 0;//锁实例private ReentrantLock rtl;public NonFairAndFairDemo(ReentrantLock rtl) {this.rtl = rtl;}@Overridepublic void run() {while (true) {//加锁rtl.lock();num++;System.out.println(Thread.currentThread().getName() + ":" + num);rtl.unlock();}}
}

测试公平锁

@Test
public void test01() {ReentrantLock reentrantLock = new ReentrantLock(true);Thread threadA = new Thread(new NonFairAndFairDemo(reentrantLock));threadA.setName("A");Thread threadB = new Thread(new NonFairAndFairDemo(reentrantLock));threadB.setName("B");threadA.start();threadB.start();
}

执行结果
在这里插入图片描述
公平向锁特征如上:按照线程的访问顺序进行获取。


测试非公平锁

@Test
public void test02() {ReentrantLock reentrantLock = new ReentrantLock(false);Thread threadA = new Thread(new NonFairAndFairDemo(reentrantLock));threadA.setName("A");Thread threadB = new Thread(new NonFairAndFairDemo(reentrantLock));threadB.setName("B");threadA.start();threadB.start();
}

执行结果
在这里插入图片描述
非公平性锁的特点,是每个线程都连续执行多次之后在替换成其他线程执行。

(2)公平锁和非公平锁的实现

abstract static class Sync extends AbstractQueuedSynchronizer

公平性锁非公平性锁的父类是syncsync类是AbstractQueuedSynchronizer是其子类,AQS是一个同步器,提供同步功能。

abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -5179523762034025860L;//加锁操作,声明是抽象方法,nofairsync和fairsync中各自实现abstract void lock();//非公平获取,公平性锁和非公平性锁都需要这个方法final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();//AQS获取state值 int c = getState();if (c == 0) {//锁空闲状态//通过cas获取锁状态,修改state状态if (compareAndSetState(0, acquires)) {//标记当前线程为获取锁的线程setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {//锁非空闲,表明锁被占中,有一种情况,当前线程即为占用锁的线程int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");//当前线程继续持有锁,仅对state进行加操作setState(nextc);return true;}return false;}//释放锁  sync中的tryRelease是公平性锁和非公平性锁的释放锁流程都是该方法protected final boolean tryRelease(int releases) {int c = getState() - releases;//只有持有锁的线程才能释放锁if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//锁才会被释放free = true;setExclusiveOwnerThread(null);}setState(c);return free;}//判断当前线程是否持有锁protected final boolean isHeldExclusively() {return getExclusiveOwnerThread() == Thread.currentThread();}final ConditionObject newCondition() {return new ConditionObject();}//获取锁的持有者线程final Thread getOwner() {return getState() == 0 ? null : getExclusiveOwnerThread();}//加锁的次数final int getHoldCount() {return isHeldExclusively() ? getState() : 0;}//是否上锁  true:表示加锁final boolean isLocked() {return getState() != 0;}
}

该Sync中方法的封装是调用AQS中的方法实现的

公平性锁和非公平锁的如何实现?

公平性锁:FairLock
static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//同步状态为空闲,需要等待队列中第一个等待着执行//什么时候当前线程可以执行? 等待队列里没有线程等待或者是有线程等待且等待的第一个线程就是当前线程if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {//当前同步状态非空闲,被线程占用且是当前线程int nextc = c + acquires;if (nextc < 0)//有符号的int类型。最高位为1表示负数throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}AbstractQueuedSynchronizer#acquirepublic final void acquire(int arg) {//当前同步状态非空闲,并且是其他线程持有锁 返回falseif (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

公平性锁获取锁流程:
1、如果同步状态为空,就可以抢锁,能够获取锁的前提条件是当前等待队列为空,或者等待队列队头是当前线程,即当前线程才能够抢锁,通过CAS抢锁(state)抢锁成功记录当前线程信息到锁上。
2、如果同步状态不为空,即存在线程占用锁且占用线程是当前线程,当前线程可成功获取锁(state)。

非公平性锁
static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;final void lock() {//执行Lock操作,尝试立即获取锁,失败就退回常规流程if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);//立即获取锁失败进入到acquire,首先调用tryAcquire}protected final boolean tryAcquire(int acquires) {//同步状态为空闲或者不为空闲但是是当前线程持有锁,返回true表示抢锁成功return nonfairTryAcquire(acquires);}}AbstractQueuedSynchronizer#acquirepublic final void acquire(int arg) {//当前同步状态非空闲,并且是其他线程持有锁 返回falseif (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}

通过代码可知:很多方法,trylock,unlock都是在父类sync实现

非公平性锁抢锁流程:
1、直接通过CAS操作抢锁,如果不成功进入常规抢锁流程。
2、获取当前锁的状态(state是否为0),如果为0表示空闲,直接通过CAS抢锁,如果成功,记录线程信息到锁上。
3、如果锁不为空闲且是当前线程持有锁,则可直接获取锁(state+1)。


重入锁的实现:
ReentrantLock都是将具体实现委托给内部类(SyncNonFairSyncFairSync)。
ReentrantLock重入次数是使用AQS的state属性,state大于0表示锁被占用(值表示当前线程重入次数),等于0表示锁空闲,小于0则表示重入次数太多导致溢出了。
可重入锁需要一个重入计数的变量,初始值为0,当成功请求锁加1,释放锁时减1,当释放锁时计数为0则真正释放锁,重入锁必须持有对锁持有者的引用,用以判断是否可以重入。

(3)Condition

synchronized与wait、notify、notifyAll方法结合可以实现等待/通知模式。reentantlock同样可以实现等待、通知模式,需要借助于Condition对象,具有更好的灵活性

newCondition方法

public Condition newCondition()

Condition中提供的方法如下:
在这里插入图片描述
awaitXXX和Object中的wait方法类似,使当前线程进入休眠等待,
signal和Object中的notify方法类似,唤醒一个处于休眠状态的线程
signalAll和Object中的signalAll方法类似,唤醒所有处于休眠状态的线程。


生产者和消费者

生产者

public class Producer extends Thread {private LinkedList<Integer> cap;//共享仓库private Random random = new Random();private ReentrantLock rlk;private Condition pToc;private Condition cTop;public Producer(LinkedList<Integer> cap, ReentrantLock rlk, Condition pToc, Condition cTop) {this.cap = cap;this.rlk = rlk;this.pToc = pToc;this.cTop = cTop;}@Overridepublic void run() {while (true) {rlk.lock();try {if (cap.size() == 3) {//缓冲区满 生产者进行阻塞System.out.println("缓冲区满");cTop.await();}//生产产品int i = random.nextInt(1000);System.out.println("生产者生产了" + i);cap.add(i);//通知消费者消费产品pToc.signal();} catch (InterruptedException e) {throw new RuntimeException(e);}rlk.unlock();}}
}

消费者

public class Consumer extends Thread {private LinkedList<Integer> cap;//共享仓库private ReentrantLock rlk;private Condition pToc;private Condition cTop;public Consumer(LinkedList<Integer> cap, ReentrantLock rlk, Condition pToc, Condition cTop) {this.cap = cap;this.rlk = rlk;this.pToc = pToc;this.cTop = cTop;}@Overridepublic void run() {while (true) {rlk.lock();try {if (cap.size() == 0) { //如果缓冲区为0,消费者阻塞System.out.println("缓冲区为空");pToc.await();}//消费者消费产品Integer i = cap.remove();System.out.println("消费者消费了" + i);//通知生产者生产cTop.signal();} catch (InterruptedException e) {throw new RuntimeException(e);}rlk.unlock();}}
}

测试类

public class Test {public static void main(String[] args) {LinkedList<Integer> cap = new LinkedList<>();ReentrantLock reentrantLock = new ReentrantLock();//生产者通知消费者Condition pToc = reentrantLock.newCondition();//消费者通知生产者Condition cTop = reentrantLock.newCondition();Producer producer = new Producer(cap,reentrantLock,pToc,cTop);Consumer consumer = new Consumer(cap,reentrantLock,pToc,cTop);producer.start();consumer.start();}
}

执行结果
在这里插入图片描述
● 在调用Condition中的await或者是signal这些方法中任何的方法时,必须持有锁(ReentantLock),如果没有持有此锁,则抛出IllegalMonitorStateException异常。
● 在调用await方法时,将释放掉锁,并在这些方法返回之前,重新先获取该锁,才能执行。
● 如果线程在等待中被中断,则等待将终止,并抛出InterruptedException,清除掉中断状态。
● 等待状态的线程按照FIFO顺序接收信号。
● 等待方法返回的线程重新获取锁的顺序与线程最初获取锁的顺序是相同的。

循环打印ABC

ABCThread类

public class ABCThread extends Thread {private String name;private ReentrantLock rtl;private Condition waitc;//等待Conditionprivate Condition sigalc; //通知Conditionpublic ABCThread(String name,ReentrantLock rtl,Condition wc,Condition sc){this.name = name;this.rtl = rtl;this.waitc = wc;this.sigalc = sc;}@Overridepublic void run() {int num =0;while (true) {rtl.lock();//等待其他线程通知,try {waitc.await();} catch (InterruptedException e) {e.printStackTrace();}//打印当前线程信息System.out.println(name);//通知下一个线程sigalc.signal();++num;if (num >= 10) break;rtl.unlock();}}
}

测试

@Test
public void test() {ReentrantLock reentrantLock = new ReentrantLock();//A通知BCondition ab = reentrantLock.newCondition();//B通知CCondition bc = reentrantLock.newCondition();//C通知ACondition ca = reentrantLock.newCondition();new ABCThread("A", reentrantLock, ca, ab).start();new ABCThread("B", reentrantLock, ab, bc).start();new ABCThread("C", reentrantLock, bc, ca).start();//先发起通知A线程reentrantLock.lock();ca.signal();reentrantLock.unlock();
}

执行结果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36540.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ReentrantLock锁相关方法

目录 Lock接口的实现类 ReentrantLock的方法 ReentrantLockTest测试 用于测试的线程 t1测试 正确释放重入锁 获取当前的重入次数 t1t2测试 使用islocked()方法检测锁状态 t1t3测试 使用trylock方法尝试获取锁 使用isHeldByCurrentThread方法检测当前线程是否持有锁 不…

ReentrantLock详解

目录 一、ReentrantLock的含义 二、RerntrantLock当中的常用方法 ①lock()和unlock()方法 ②构造方法 ③tryLock()方法 tryLock()无参数 tryLock(timeout,Times)有参数 ④lockInterruptibly() throws InterruotedException 经典面试问题: ReentrantLock和synchronized有什…

OpenAI最新官方ChatGPT聊天插件接口《智能聊天插件引言》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(一)(附源码)

Chat Plugins Limited Alpha 聊天插件 前言IntroductionPlugin flow 插件流其它资料下载 Learn how to build a plugin that allows ChatGPT to intelligently call your API. 了解如何构建允许ChatGPT智能调用API的插件。 前言 在现代的软件开发环境中&#xff0c;使用第三方…

Pycharm快速入门(10) — 插件管理

1、插件安装 File | Settings | Plugins | Marketplace 搜索插件点击Install安装 2、插件卸载 File | Settings | Plugins | Installed 选择需要卸载的插件&#xff0c;点击Uninstall。 3、推荐插件 &#xff08;1&#xff09;、Chinese ​(Simplified)​ Language Pack &am…

chatgpt赋能python:Python编程的好玩之处:用简单的代码创造奇妙的世界

Python编程的好玩之处&#xff1a;用简单的代码创造奇妙的世界 如果你喜欢写代码&#xff0c;那么Python是一个不错的选择。Python语言设计简单&#xff0c;易学易用&#xff0c;同时还拥有丰富的生态系统&#xff0c;支持许多强大的第三方库和框架&#xff0c;可以使你轻松地…

chatgpt赋能python:Python图片拼图的好处和应用

Python图片拼图的好处和应用 Python是一种高级编程语言&#xff0c;已经被广泛应用于数据科学、网络编程、机器学习等领域。其中&#xff0c;Python的图像处理领域也越来越受关注。在本文中&#xff0c;我们将介绍如何使用Python创建图片拼图&#xff0c;并讨论它的好处和应用…

midjourney教程:如何快速生成个性化Logo设计

midjourney是一款基于人工智能技术的Logo设计工具&#xff0c;它可以帮助用户快速生成个性化的Logo设计&#xff0c;而无需具备专业的设计技能。下面将为大家介绍midjourney的使用方法&#xff0c;以帮助大家轻松生成符合自己需求的Logo设计。 第一步&#xff1a;登录midjourn…

chatgpt赋能python:Python添加图片背景的方法

Python添加图片背景的方法 简介 Python是一种开源的高级编程语言&#xff0c;广泛应用于各个行业中&#xff0c;包括图像处理。添加图片背景是图像处理中的常见需求&#xff0c;通过Python可以很方便地实现。 本篇文章将介绍如何使用Python来给图片添加背景&#xff0c;让您…

chatgpt赋能python:Python怎么做图形

Python怎么做图形 在数据可视化和图像处理方面&#xff0c;Python已经成为了最受欢迎的编程语言之一。Python的图形库使得创建各种图形和图表、可视化工具和图像处理应用程序变得容易而简单。 在本文中&#xff0c;我们将会介绍一些最受欢迎的Python图形库&#xff0c;以帮助…

程序员晒追女神聊天截图,坦言第一次没经验,网友直呼凭实力单身

前段时间网络上一名程序员晒出了自己与女神之间的聊天记录的对话截图&#xff0c;通过截图中我们可以看出&#xff0c;应该是这位程序员在追求这位女神&#xff0c;但是短短的十几分钟几条聊天记录&#xff0c;却以女神不再愿意搭理程序员结束&#xff0c;对于这样的结局&#…

程序员给女友4千生活费,收到女友错发信息后分手,神对话!

如何平衡好亲情爱情的关系&#xff0c;是一门学问&#xff0c;有的人就希望自己的另一半过好他们自己的小日子&#xff0c;不要对家里的事情过多的付出&#xff0c;但有人觉得自己父母养大自己不容易&#xff0c;能有能力的话&#xff0c;不光孝敬爹妈&#xff0c;还会帮衬家里…

程序员就是这样聊天把女朋友聊没的

身为程序员 都想当然的认为 身为一个优秀的程序员 我怎么可能会没女票 这不科学啊 工资高&#xff0c;话少 有一天看到了 某个程序员的聊天记录 有女孩主动搭讪 这么绝好的机会 然后你竟然说忙 说忙 忙... 主动找你搭讪 你还不抓紧机会约约约 如果改成&#xff1a…

被程序员的相亲规划整不会了......

近日&#xff0c;北京一程序员将自己7天7场相亲行程规划表发到论坛分享&#xff0c;感叹到&#xff1a;真不是凡尔赛&#xff0c;相亲比上班还难&#xff0c;引来大量网友围观。 相亲也有规划表&#xff1f; 据介绍&#xff0c;该程序员今年刚好30岁&#xff0c;自己平时加班多…

程序员吐槽女朋友狮子大开口

本文转载自程序员八卦 一个程序员发帖吐槽自己的潮汕女朋友&#xff0c;开口要彩礼18万8&#xff0c;楼主在网上查了一下&#xff0c;一般潮汕彩礼是3万到8万&#xff0c;难道外地人要多给一点吗&#xff1f;而且女朋友还一定要楼主父母出彩礼&#xff0c;不能楼主自己出&…

最最普通程序员,如何利用工资攒够彩礼,成为人生赢家

今天我们不讲如何提升你的专业技能去涨工资&#xff0c;不讲面试技巧如何跳槽涨工资&#xff0c;不讲如何干兼职赚人生第一桶金&#xff0c;就讲一个最最普通的程序员&#xff0c;如何在工作几年后&#xff0c;可以攒够彩礼钱&#xff0c;婚礼酒席钱&#xff0c;在自己人生大事…

如何做好小红书?从找好定位开始,这篇文章告诉你

近年来小红书随着用户体量壮大和平台多元化发展&#xff0c;用户的兴趣点&#xff0c;早已从美妆独大变为渗透生活领域的各个方面。与以往相比&#xff0c;大家对小红书的认知也逐渐在发生变化。 如果说去年还有不少商家还经常问我们“为什么要做小红书&#xff1f;”。那么&am…

测试听力口语软件,上、英语系学姐最全整理的34个英语学习App 针对听力、口语、阅读...

英语的重要性不用我多说啦~日常生活、工作&#xff0c;不擅长英语真的会失去很多机会和乐趣 作为英语系学姐今天就给大家总结了一些学习英语的app 有需要就马住&#xff0c;慢慢学习&#xff01; 听力 听力学习&#xff0c;都非常好用 -朗易思听 页面超精美&#xff0c;资源也很…

小红书怎么运营好?分享小红书的一些经验让你少走弯路

每次讲小红书运营&#xff0c;我都尽量把一个问题拆的特别细&#xff0c;揉碎了讲&#xff0c;说实话挺不容易的。之前也发过&#xff0c;这次分享又是小红书&#xff0c;没办法&#xff0c;小红书的流量非常大&#xff0c;而且粉丝精准度也很不错。 分享的这些都是经验&#…

chatgpt赋能python:Python手机密码解锁-打开手机的一条捷径

Python手机密码解锁-打开手机的一条捷径 我们都遇到过忘记手机密码的经历。不管是因为长时间不用手机导致遗忘&#xff0c;还是输入错误太多次&#xff0c;导致手机被锁定&#xff0c;让我们感到非常困扰和苦恼。虽然我们可以通过向手机厂商寻求帮助或找专业维修技术人员来解锁…

16个小的UI设计规则却能产生巨大的影响

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的&#xff0c;我们出的钱 体验地…