iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么在Java中使用ReentrantLock实现并发编程
  • 280
分享到

怎么在Java中使用ReentrantLock实现并发编程

2023-06-15 05:06:38 280人浏览 独家记忆
摘要

这篇文章给大家介绍怎么在Java中使用ReentrantLock实现并发编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、首先看图二、lock()跟踪源码这里对公平锁和非公平锁做了不同实现,由构造方法参数决定是否公

这篇文章给大家介绍怎么在Java中使用ReentrantLock实现并发编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

一、首先看图

怎么在Java中使用ReentrantLock实现并发编程

二、lock()跟踪源码

怎么在Java中使用ReentrantLock实现并发编程

这里对公平和非公平锁做了不同实现,由构造方法参数决定是否公平。

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

2.1 非公平锁实现

static final class NonfairSync extends Sync {    private static final long serialVersionUID = 7316153563782823691L;        final void lock() {        if (compareAndSetState(0, 1))            setExclusiveOwnerThread(Thread.currentThread());        else            acquire(1);    }    protected final boolean tryAcquire(int acquires) {        return nonfairTryAcquire(acquires);    }}

代码量很少。首先compareAndSetState(0, 1)通过CAS(期望值0,新值1,内存值stateOffset)

  • 如果修改成功,即抢占到锁,setExclusiveOwnerThread(Thread.currentThread());将AQS中的变量exclusiveOwnerThread设置为当前抢占到锁的线程,也就是图中的ThreadA。

  • 若没有抢占成功,证明此时锁被占用,执行方法acquire(1);

public final void acquire(int arg) {    if (!tryAcquire(arg) &&        acquireQueued(addWaiter(node.EXCLUSIVE), arg))        selfInterrupt();}

这里主要看两个方法tryAcquire(arg)acquireQueued(addWaiter(Node.EXCLUSIVE), arg)。当满足if条件后,会给当前线程标记一个interrupt状态。

2.1.1 tryAcquire(arg)

这个方法又有多个实现。这里看NonfairSync非公平锁。

怎么在Java中使用ReentrantLock实现并发编程

protected final boolean tryAcquire(int acquires) {    return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {     final Thread current = Thread.currentThread();     int c = getState();     if (c == 0) {         if (compareAndSetState(0, acquires)) {             setExclusiveOwnerThread(current);             return true;         }     }     else if (current == getExclusiveOwnerThread()) {         int nextc = c + acquires;         if (nextc < 0) // overflow             throw new Error("Maximum lock count exceeded");         setState(nextc);         return true;     }     return false; }

在这个方法中,还不死心,首先会判断下AQS中的state是否为0,为0也就是说距离上次尝试获取锁到现在准备进入队列(双向链表)中这段时间内,锁已经被释放,可以重新CAS尝试获取锁。

如果当前锁还是被持有状态,就是state!=0,就会判断,当前线程是不是当前持有锁的线程exclusiveOwnerThread,如果是,则state+1,从这里可以看出state表示的是重入次数。

全部不满足,返回false。

2.1.2 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

addWaiter

private Node addWaiter(Node mode) {    Node node = new Node(Thread.currentThread(), mode);    // Try the fast path of enq; backup to full enq on failure    Node pred = tail;    if (pred != null) {        node.prev = pred;        if (compareAndSetTail(pred, node)) {            pred.next = node;            return node;        }    }    enq(node);    return node;}

tryAcquire(arg)返回false,证明当前线程还是没有获取到锁。那么就要进入队列等待了,首先addWaiter方法,将当前线程封装成一个Node,如果pred不为空,则将当前节点做链表的尾部插入,同时为了防止在此期间前序节点已经不在队列中了,也会运用CAS操作来执行(期望值pred,新值node,内存值tailOffset)。

如果前序节点为空,或者在CAS时发现前序节点已经不存在了,则重新构建链表,将当前节点封装的Node,加入到链表当中。

private Node enq(final Node node) {    for (;;) {        Node t = tail;        if (t == null) { // Must initialize            if (compareAndSetHead(new Node()))                tail = head;        } else {            node.prev = t;            if (compareAndSetTail(t, node)) {                t.next = node;                return t;            }        }    }}

加入完成后,返回当前node节点,进入acquireQueued方法。

acquireQueued

final boolean acquireQueued(final Node node, int arg) {    boolean failed = true;    try {        boolean interrupted = false;        for (;;) {        //获取到当前node节点的上一个节点            final Node p = node.predecessor();            //如果当前的上个节点就是头节点,会再次尝试获取锁            if (p == head && tryAcquire(arg)) {            //获取成功,将当前节点置空,并成为新的头节点                setHead(node);//这个p已经没用了,防止内存泄漏,直接指向null,下次GC时回收                p.next = null; // help GC                //不需要取消                failed = false;                //return false,不需要中断当前线程                return interrupted;            }            if (shouldParkAfterFailedAcquire(p, node) &&                parkAndCheckInterrupt())                interrupted = true;        }    } finally {        if (failed)            cancelAcquire(node);    }}

这里是一个自旋操作,首先拿到当前线程封装节点的上一个节点,如果满足第一个if条件if (p == head && tryAcquire(arg)),证明上个节点为头节点,则此时当前线程也会再次尝试获取锁,获取锁成功,证明此时没有别的线程在队列中了,则将当前node清空并设置为头节点,返回不需要中断当前线程。

在第二个if条件中if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())。走到这里证明当前线程不是第一个线程节点,或者没有抢占到锁,shouldParkAfterFailedAcquire这个方法见名知意,在抢占失败后是否需要park阻塞,里面主要是用于清理双向链表中被取消的节点线程和未被阻塞的节点线程。

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {    int ws = pred.waitStatus;//获取前置节点的等待状态    if (ws == Node.SIGNAL)//前置节点的等待状态为-1,表示前置节点在队列中阻塞,那么当前节点也需要被阻塞在队列中        return true;    if (ws > 0) {//前置节点等待状态大于0,此前置节点已经被取消,循环遍历清除所有已被取消的节点。        do {            node.prev = pred = pred.prev;        } while (pred.waitStatus > 0);        pred.next = node;    } else {//前置节点等待状态小于等于0,且不等于-1,也就是没有被阻塞也没有被取消//则将前置节点设置为阻塞状态。        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);    }    return false;}
  • 前置节点的等待状态为-1,表示前置节点在队列中阻塞,那么当前节点也需要被阻塞在队列中

  • 前置节点等待状态大于0,此前置节点已经被取消,循环遍历清除所有已被取消的节点。

  • 前置节点等待状态小于等于0,且不等于-1,也就是没有被阻塞也没有被取消。则将前置节点设置为阻塞状态。

到这里,基于非公平锁的实现结束。

2.2 公平锁实现

公平锁和乐观锁的区别就在于,非公平锁acquire(1)前会先尝试获取锁,公平锁直接acquire(1)

static final class FairSync extends Sync {        private static final long serialVersionUID = -3000897897090466540L;        final void lock() {            acquire(1);        }}
2.2.1 tryAcquire(arg)

在tryAcquire中也和非公平锁有一定的区别。在当前锁没有被占有时。非公平锁不用考虑目前AQS队列中的排队情况,直接通过CAS尝试获取锁。公平锁会看目前队列的状态,再来决定是尝试占有锁还是在队列中等待。

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)           throw new Error("Maximum lock count exceeded");       setState(nextc);       return true;   }   return false;}

java基本数据类型有哪些

Java的基本数据类型分为:1、整数类型,用来表示整数的数据类型。2、浮点类型,用来表示小数的数据类型。3、字符类型,字符类型的关键字是“char”。4、布尔类型,是表示逻辑值的基本数据类型。

关于怎么在Java中使用ReentrantLock实现并发编程就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 怎么在Java中使用ReentrantLock实现并发编程

本文链接: https://www.lsjlt.com/news/278029.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么在Java中使用ReentrantLock实现并发编程
    这篇文章给大家介绍怎么在Java中使用ReentrantLock实现并发编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、首先看图二、lock()跟踪源码这里对公平锁和非公平锁做了不同实现,由构造方法参数决定是否公...
    99+
    2023-06-15
  • 怎么在JAVA中使用ReentrantLock实现并发
    这期内容当中小编将会给大家带来有关怎么在JAVA中使用ReentrantLock实现并发,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1. 介绍结合上面的ReentrantLock类图,Reentrant...
    99+
    2023-06-15
  • Java多线程并发ReentrantLock怎么使用
    这篇文章主要介绍“Java多线程并发ReentrantLock怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java多线程并发ReentrantLock怎么使用”文章能帮助大家解决问题。背景...
    99+
    2023-07-02
  • Java并发中ReentrantLock锁怎么用
    这篇文章主要讲解了“Java并发中ReentrantLock锁怎么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java并发中ReentrantLock锁怎么用”吧!重入锁可以替代关键字 ...
    99+
    2023-06-21
  • 怎么在Java中使用CountDownLatch实现并发编程
    本篇文章为大家展示了怎么在Java中使用CountDownLatch实现并发编程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、We...
    99+
    2023-06-14
  • Java并发编程之ReentrantLock实现原理及源码剖析
    目录一、ReentrantLock简介二、ReentrantLock使用三、ReentrantLock源码分析1、非公平锁源码分析2、公平锁源码分析前面《Java并发编程之JUC并发...
    99+
    2022-11-12
  • 怎么在Java中利用LockSupport类实现并发编程
    今天就跟大家聊聊有关怎么在Java中利用LockSupport类实现并发编程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、LockSupport类的属性private ...
    99+
    2023-06-15
  • 浅谈Java并发中ReentrantLock锁应该怎么用
    目录1、重入锁说明2、中断响应说明3、锁申请等待限时tryLock(long, TimeUnit)tryLock()4、公平锁说明源码(JDK8)重入锁可以替代关键字 synchro...
    99+
    2022-11-12
  • 在java项目中使用线程池实现并发编程
    今天就跟大家聊聊有关在java项目中使用线程池实现并发编程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、任务和执行策略之间的隐性耦合Executor可以将任务的提交和任务的执行策...
    99+
    2023-05-31
    java 线程池 并发编程
  • 如何使用NPM在Java和NumPy中实现并发编程?
    随着计算机科学的不断发展,多核处理器的出现使得并发编程成为了一种重要的编程方式。并发编程可以大大提高程序的性能和响应能力,减少等待时间,提高程序的可靠性。但是,并发编程也面临着很多挑战,如竞态条件、死锁等问题。为了解决这些问题,我们需要使...
    99+
    2023-07-23
    numy 并发 npm
  • 怎么在java中利用ReentrantLock实现重入测试
    本篇文章给大家分享的是有关怎么在java中利用ReentrantLock实现重入测试,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的特点有哪些Java的特点有哪些1.J...
    99+
    2023-06-14
  • 如何在Java中利用CyclicBarrier实现并发编程
    如何在Java中利用CyclicBarrier实现并发编程?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。  使用JAVA编写并发程序的时候,我们需要仔...
    99+
    2023-05-31
    java 并发编程 cyclicbarrier
  • 怎么在java中实现多线程高并发
    这篇文章将为大家详细讲解有关怎么在java中实现多线程高并发,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1.JMM数据原子操作read(读取)∶从主内存读取数据load(载入):将主内存读...
    99+
    2023-06-14
  • Java并发编程ThreadLocalRandom类怎么使用
    本篇内容介绍了“Java并发编程ThreadLocalRandom类怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么需要Thre...
    99+
    2023-07-02
  • 多线程并发编程如何在Java项目中实现
    本篇文章为大家展示了多线程并发编程如何在Java项目中实现 ,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、多线程操作系统有两个容易混淆的概念,进程和线程。进程:一个计算机程序的运行实例,包含了需...
    99+
    2023-05-31
    java 多线程 并发编程
  • Java并发编程中死锁的实现
    这篇文章给大家介绍Java并发编程中死锁的实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、什么是死锁所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进二、死锁产生的...
    99+
    2023-06-15
  • DelayQueue怎么在Java多线程并发开发中使用
    这篇文章给大家介绍DelayQueue怎么在Java多线程并发开发中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。此接口的实现必须定...
    99+
    2023-05-31
    java delayqueue 多线程并发
  • Java并发编程之线程安全性怎么实现
    今天小编给大家分享一下Java并发编程之线程安全性怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.什么是线程安全性...
    99+
    2023-06-29
  • 如何在Java中使用Django进行并发编程?
    在Java开发中,Django是一个非常流行的Python web框架,它的并发编程能力也备受推崇。本篇文章将介绍如何在Java中使用Django进行并发编程,同时穿插一些演示代码。 一、Django的并发编程能力 Django的并发编程能...
    99+
    2023-10-16
    git django 并发
  • 在Java项目中实现多线程并发编程的方法
    在Java项目中实现多线程并发编程的方法?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java 中的锁通常分为两种:通过关键字 synchronized 获取的...
    99+
    2023-05-31
    并发 java并发 多线程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作