广告
返回顶部
首页 > 资讯 > 后端开发 > Python >java Semaphore共享锁实现原理解析
  • 345
分享到

java Semaphore共享锁实现原理解析

Semaphore共享锁java 锁 2023-01-09 12:01:57 345人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录正文Semaphore内部类及继承关系Semaphore.acquire流程分析(以非公平锁为例)tryAcquireShareddoAcquireSharedInterrupt

正文

线程间通信方式中,我们了解到可以使用Semaphore信号量来实现线程间通信,Semaphore支持公平锁和非公平锁,Semaphore底层是通过共享锁来实现的,其支持两种构造函数,如下所示:

 // 默认使用非公平锁实现
 public Semaphore(int permits) {
     sync = new NonfairSync(permits);
 }
 ​
 public Semaphore(int permits, boolean fair) {
     sync = fair ? new FairSync(permits) : new NonfairSync(permits);
 }

Semaphore提供的常用函数如下所示:

函数名说明备注
acquire获取锁/
release释放锁/

下面我们来看下Semaphore内部的实现原理

Semaphore内部类及继承关系

可以看出Semaphore和ReentrantLock实现原理基本一致,包含NonfairSync和FairSync两个内部类,这两个内部类的父类均为AQS,不妨大胆猜测Semaphore也是依赖AQS实现的,接下来我们一起来看下Semaphore获取和释放锁的流程。

Semaphore.acquire流程分析(以非公平锁为例)

从上图可以看出,针对阻塞线程的部分实现,和ReentrantLock基本一致,我们不做赘述,主要来看下前半部分的源码实现:

 // Semaphore.java
 public void acquire() throws InterruptedException {
     sync.acquireSharedInterruptibly(1);
 }
 // AbstractQueuedSynchronizer.java
 public final void acquireSharedInterruptibly(int arg)
         throws InterruptedException {
     // 如果线程是中断状态,抛出异常
     if (Thread.interrupted())
         throw new InterruptedException();
     // 尝试获取共享资源
     if (tryAcquireShared(arg) < 0)
         doAcquireSharedInterruptibly(arg);
 }

从源码可以看出acquire主要依赖于tryAcquireShared和doAcquireSharedInterruptibly,接下来我们来分别看下这两块的代码

tryAcquireShared

 // NonfairSync
 protected int tryAcquireShared(int acquires) {
     return nonfairTryAcquireShared(acquires);
 }
 // Sync
 final int nonfairTryAcquireShared(int acquires) {
     for (;;) {
         int available = getState();
         int remaining = available - acquires;
         if (remaining < 0 ||
             compareAndSetState(available, remaining))
             return remaining;
     }
 }
 // AbstractQueuedSynchronizer.java
 protected final boolean compareAndSetState(int expect, int update) {
     // See below for intrinsics setup to support this
     return unsafe.compareAndSwapint(this, stateOffset, expect, update);
 }

从代码可以看出这里主要是根据申请的许可证数量,比较时否有许可证数量,如果可用许可证数量小于0,则直接返回,如果大于0,则通过CAS将state设置为可用许可证数量。

doAcquireSharedInterruptibly

当tryAcquireShared中返回的可用许可证数量小于0时,执行doAcquireSharedInterruptibly流程,代码如下:

 // AbstractQueuedSynchronizer.java
 // 在队尾新建node对象并添加
 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;
 }
 // AbstractQueuedSynchronizer.java
 private void doAcquireSharedInterruptibly(int arg)
     throws InterruptedException {
     // 将当前线程添加到等待队列
     final Node node = addWaiter(Node.SHARED);
     boolean failed = true;
     try {
         // for循环自旋
         for (;;) {
             // 获取node的前一个节点
             final Node p = node.predecessor();
             // 如果前一个节点是头节点
             if (p == head) {
                 // 尝试获取锁
                 int r = tryAcquireShared(arg);
                 if (r >= 0) {
                     // 获取锁成功,更新node信息设置为头节点,并通知其他节点
                     setHeadAndPropagate(node, r);
                     p.next = null; // help GC
                     failed = false;
                     return;
                 }
             }
             // 判断是否需要阻塞线程,设置waitStatus并阻塞
             if (shouldParkAfterFailedAcquire(p, node) &&
                 parkAndCheckInterrupt())
                 throw new InterruptedException();
         }
     } finally {
         if (failed)
             cancelAcquire(node);
     }
 }
private void setHeadAndPropagate(Node node, int propagate) {
    Node h = head; // Record old head for check below
    setHead(node);
    if (propagate > 0 || h == null || h.waitStatus < 0 ||
        (h = head) == null || h.waitStatus < 0) {
        Node s = node.next;
        if (s == null || s.isshared())
            doReleaseShared();
    }
}

执行setHeadAndPropagate的主要目的在于,这里能获取到说明在该线程自旋过程中有线程释放了许可证,释放的许可证数量有可能还有剩余,所以传递给其他节点的线程,唤醒其他阻塞状态的线程也尝试去获取许可证。

Semaphore.release流程分析(以非公平锁为例)

Semaphore.release流程相对而言,就比较简单,将release传递到AQS内部通过CAS更新许可证数量信息,更新完成后,遍历队列中Node节点,将Node waitStatus设置为0,并对对应线程执行unpark,相关代码如下:

protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        int current = getState();
        int next = current + releases;
        if (next < current) // overflow
            throw new Error("Maximum permit count exceeded");
        // 通过CAS更新许可证数量
        if (compareAndSetState(current, next))
            return true;
    }
}
private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}
// 许可证数量更新完成后,调用该方法唤醒线程
private void doReleaseShared() {
    // 自旋
    for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            if (ws == Node.SIGNAL) {
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                // 唤醒后继节点线程抢占许可证
                unparkSuccessor(h);
            }
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        if (h == head)                   // loop if head changed
            break;
    }
}

综上,我们分析了Smaphore非公平锁的实现,感兴趣的可以分析下公平锁的实现,其本质区别在于在tryAcquireShared中只有当等待队列为空时,才会去尝试更新剩余许可证数量

以上就是Semaphore共享锁实现原理解析的详细内容,更多关于Semaphore共享锁的资料请关注编程网其它相关文章!

--结束END--

本文标题: java Semaphore共享锁实现原理解析

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

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

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

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

下载Word文档
猜你喜欢
  • java Semaphore共享锁实现原理解析
    目录正文Semaphore内部类及继承关系Semaphore.acquire流程分析(以非公平锁为例)tryAcquireShareddoAcquireSharedInterrupt...
    99+
    2023-01-09
    Semaphore共享锁 java 锁
  • 如何深层透析Java Socket共享的设计原理
    今天就跟大家聊聊有关如何深层透析Java Socket共享的设计原理,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java Socket共享在使用的时候有很多的问题需要我们解决,其实...
    99+
    2023-06-17
  • MySQL InnoDB锁类型及锁原理实例解析
    目录锁共享锁排他锁意向锁记录锁间隙锁临键锁死锁死锁产生条件行锁发生死锁表锁发生死锁锁的释放事务阻塞死锁的避免锁的日志行锁的原理不带任何索引的表带主键索引的表带唯一索引的表结论1.表必定有索引2.唯一索引数据行加锁,主键索...
    99+
    2022-11-27
    MySQL InnoDB锁类型锁原理 MySQL InnoDB 锁
  • Java CompletableFuture实现原理分析详解
    目录简介CompletableFuture类结构CompletableFuture回调原理CompletableFuture异步原理总结简介 前面的一篇文章你知道Java8并发新特性...
    99+
    2022-11-13
  • java LockSupport实现原理示例解析
    目录引言LockSupport常见函数LockSupport.parkLockSupport.unpark引言 前文中了解到AQS借助LockSupport.park和LockSup...
    99+
    2023-01-09
    java LockSupport原理 java LockSupport
  • AndroidLock锁实现原理详细分析
    目录Lock简介synchronized和lock的区别写个Demolock源码总结Lock简介 Lock接口位于J.U.C下locks包内,其定义了Lock应该具备的方法。 Loc...
    99+
    2023-02-17
    Android Lock锁 Android Lock锁原理
  • 数据库内存共享实现原理是什么
    这篇文章主要讲解了“数据库内存共享实现原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“数据库内存共享实现原理是什么”吧!共享内存是进程间通讯的一种方...
    99+
    2022-10-18
  • 详解Java ReentrantReadWriteLock读写锁的原理与实现
    目录概述原理概述加锁原理图解过程源码解析解锁原理图解过程源码解析概述 ReentrantReadWriteLock读写锁是使用AQS的集大成者,用了独占模式和共享模式。本文和大家一起...
    99+
    2022-11-13
    Java ReentrantReadWriteLock读写锁 Java ReentrantReadWriteLock Java 读写锁
  • Java中怎么利用多线程锁实现数据同步共享
    Java中怎么利用多线程锁实现数据同步共享,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。大多数应用程序要求线程互相通信来同步它们的动作。在Java程序中最简单实现同步的方法就是...
    99+
    2023-06-17
  • Java并发程序刺客之假共享的原理及复现
    目录前言假共享(False Sharing)缓存行假共享Java代码复现假共享复现假共享JDK解决假共享从更低层次C语言看假共享总结前言 前段时间在各种社交平台“雪糕刺客...
    99+
    2022-11-13
    Java并发程序 假共享 Java 假共享 Java 并发程序
  • GolangWaitGroup实现原理解析
    原理解析 type WaitGroup struct { noCopy noCopy // 64-bit value: high 32 bits are counter,...
    99+
    2023-02-03
    Go WaitGroup Go WaitGroup实现原理
  • reacthooks实现原理解析
    目录react hooks 实现Hooks 解决了什么问题Hooks API 类型首先接触到的是 State hooks其次接触到的是 Effect hooks最后接触到的是 cus...
    99+
    2022-11-13
  • 深入剖析OpenMP锁的原理与实现
    目录前言深入分析 omp_lock_tomp_lock_t 源码分析深入分析 omp_nest_lock_tomp_nest_lock_t 源码分析源代码函数名称不同的原因揭秘总结前...
    99+
    2023-01-28
    OpenMP锁原理 OpenMP锁实现 OpenMP锁
  • Java如何实现共享租车信息管理系统
    这篇文章主要介绍Java如何实现共享租车信息管理系统,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!基于servlet+jsp+jdbc的后台管理系统,包含5个模块:汽车账户部管理、租车账户部管理、汽车信息管理表、租车...
    99+
    2023-06-29
  • redis分布式锁的实现原理实例分析
    这篇文章主要介绍了redis分布式锁的实现原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇redis分布式锁的实现原理实例分析文章都会有所收获,下面我们一起来看看吧。首先,为了确保分布式锁可用,我们至...
    99+
    2023-06-29
  • Java网络编程之UDP实现原理解析
    UDP实现通信非常简单,没有服务器,每个都是客户端,每个客户端都需要一个发送端口和一个接收端口。一个客户端向另一个客户端发送消息时,需要知道对方的IP和接收端口,所用到的类为Data...
    99+
    2022-11-12
  • Java详解HashMap实现原理和源码分析
    目录学习要点:1、什么是HashMap?2、HashMap的特性3、HashMap的数据结构4、HashMap初始化操作4.1、成员变量4.2、 构造方法5、Jdk8中HashMap...
    99+
    2022-11-12
  • Java中锁的实现原理和实例用法
    这篇文章主要介绍“Java中锁的实现原理和实例用法”,在日常操作中,相信很多人在Java中锁的实现原理和实例用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中锁的实现原理和实例用法”的疑惑有所帮助!...
    99+
    2023-06-16
  • Vue3 KeepAlive实现原理解析
    目录思路代码解析setuprenderonActivated 和 onDeactived调用思路 首先我们知道 KeepAlive 是一个内置组件,那封装一个组件对于大家来说应该不会...
    99+
    2022-11-13
  • Java实现读写锁的原理是什么
    本文小编为大家详细介绍“Java实现读写锁的原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java实现读写锁的原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。读/写锁Java实现首先我们总结一...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作