首页 > 编程语言 >Semaphore源码解析

Semaphore源码解析

时间:2024-03-19 11:01:21浏览次数:19  
标签:Node node head null int 源码 ws Semaphore 解析

Semaphore

https://www.bilibili.com/video/BV1Ae411C7xr/

public class Semaphore implements java.io.Serializable

同Reetrantlock在Sync 继承AQS

abstract static class Sync extends AbstractQueuedSynchronizer

可以指定Sync是否是公平锁,默认非公平

permits为设置AQS内state数==可以共享线程数

public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}
public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

tryAcquireShared默认非公平锁实现去扣减许可数,如果remaining>=0,执行CAS设置,并直接返回remaining

如果remaining < 0,执行doAcquireSharedInterruptibly(arg);

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    //初始添加虚拟头节点 -> node
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //设置虚拟头节点为signal 然后当前线程阻塞
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

假设有4个线程,设置new Semaphore(2)

t1,t2,t3,t4,其中t1,t2运行

等待队列dual->t3->t4,dual和t3 的ws为signal状态,t3和t4为阻塞状态

t1释放共享锁

public final boolean (int arg) {
    //tryReleaseShared实现方法.增加state数量
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
private void doReleaseShared() {
    for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            if (ws == Node.SIGNAL) {
                //将dual头节点ws改为0
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                //释放t3节点
                unparkSuccessor(h);
            }
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        if (h == head)                   // loop if head changed
            break;
    }
}
private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    //t3=dual.next
    Node s = node.next;
    //t3!=null 并且 t3.ws=sigal
    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)
        //释放t3线程
        LockSupport.unpark(s.thread);
}

如果此时运行的线程t2也释放,t2线程执行代码,此时执行完毕t4线程仍阻塞

private void doReleaseShared() {
    for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            //此时的head ws=0
            if (ws == Node.SIGNAL) {
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                unparkSuccessor(h);
            }
            //所以设置head ws=PROPAGATE
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
		//然后退出循环
        if (h == head)                   // loop if head changed
            break;
    }
}

但是t1线程执行unpark,回到t1线程

doAcquireShared方法parkAndCheckInterrupt()内退出阻塞

进行循环

private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    if (interrupted)
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

node是t3节点

private void setHeadAndPropagate(Node node, int propagate) {
    Node h = head; // Record old head for check below
    //已设置t3为head
    setHead(node);
 	//此时h是老头节点,h!=null并且h.ws=propagate 满足h.waitStatus < 0
    if (propagate > 0 || h == null || h.waitStatus < 0 ||
        (h = head) == null || h.waitStatus < 0) {
        Node s = node.next;
        if (s == null || s.isShared())
            //释放t4节点
            doReleaseShared();
    }
}

标签:Node,node,head,null,int,源码,ws,Semaphore,解析
From: https://www.cnblogs.com/wsyphaha/p/18082289

相关文章

  • 多行业万能预约门店小程序源码系统 带完整的搭建教程以及安装代码包
    在数字化转型的大趋势下,门店预约服务已经成为提升客户体验、优化资源配置的关键环节。然而,市面上的预约系统往往功能单一,难以满足多行业的需求。小编给大家分享一款多行业万能预约门店小程序源码系统。该系统不仅具备高度的可定制性,还提供了丰富的功能模块,能够轻松应对不同行业......
  • 校园跑腿小程序源码系统 取快递+寄快递+食堂超市代买功能 带完整的安装代码包以及搭建
    在数字化、智能化的今天,校园生活的便捷性成为了学生们越来越关注的话题。为了满足校园内日益增长的服务需求,一款集取快递、寄快递、食堂超市代买等多功能于一体的校园跑腿小程序源码系统应运而生。该系统不仅提供了完整的安装代码包,还附带了详尽的搭建教程,让使用者能够轻松搭建......
  • php站群程序24年苹果cms影视站泛目录站群源码模板权重神器
    php站群程序24年苹果cms影视站泛目录站群源码模板权重神器演示地址:http://fan.chinabic.com/程序简介:2024年新版,可以看截图2月28日蜘蛛统计1、基于苹果CMS二次开发,包苹果CMS基础功能。2、支持实际在线视频播放,增加泛目录功能,并且泛内页同时能正常播放视频内容。3、自......
  • Python轻松实现地图可视化(附详细源码) 转载
    大家好,我是J哥,专注原创,致力于用浅显易懂的语言分享爬虫、数据分析及可视化等干货,希望人人都能学到新知识。Python的地图可视化库很多,Matplotlib库虽然作图很强大,但只能做静态地图。而我今天要讲的是交互式地图库,分别为pyecharts、folium,掌握这两个库,基本可以解决你的地图可视化需......
  • ubuntu域名解析暂时失效解决办法
    你好!如果你在Ubuntu虚拟机中遇到域名解析失效的问题,我可以提供一些解决方法。请注意,以下方法适用于VMware虚拟机中的Ubuntu。修改DNS设置:打开终端(命令行)。输入以下命令以编辑resolv.conf文件:sudovi/etc/resolv.conf进入编辑模式(按i键)。在文件中添加以......
  • vue面试题(vue2响应式源码剖析)
    一、前言这篇文章结合Vue2.7.16的源码和一个Vue2的项目,来详细讲解Vue2实现响应式数据的核心代码1.1准备安装@vue/clinpminstall-g@vue/cli创建vue项目vuecreatevue2-test修改Vue实例的配置对象二、响应式处理的入口通过newVue()调用Vue构造函数,......
  • 【20.5】Django框架Form组件之源码
    【一】切入点切入点form_obj.is_valid()defis_valid(self):"""ReturnTrueiftheformhasnoerrors,orFalseotherwise."""returnself.is_boundandnotself.errors如果is_valid要想返回True那么self.is_bound要为Trueself.errors......
  • AI换脸神器A kool全面解析:超简单1分钟操作,创意爆棚,商业前景广阔!
    大家好,今天我要给大家介绍一款超级好用的AI换脸工具-Akool。这款工具不仅简单易用,而且在数字营销领域有着广泛的应用,比如定制写真、影视换脸、虚拟网红、短剧出海等等。听起来是不是很神奇呢?接下来,我就带大家一起了解一下这款神奇的AI换脸工具。一、Akool简介Akool是一......
  • Java毕业设计-基于SSM框架的学生成绩管理系统项目实战(附源码+论文)
    大家好!我是岛上程序猿,感谢您阅读本文,欢迎一键三连哦。......
  • 【前端素材】推荐优质综合购物电子商城网站设计Cropium平台模板(附源码)
    一、需求分析在线电子数码商店网站是指专门销售电子产品和数码设备的网上商店。这类网站通常提供广泛的产品选择,涵盖手机、平板电脑、相机、电脑配件、智能家居设备等多种数码产品。以下是在线电子数码商店网站的一般功能:产品展示与购买: 网站上展示各种电子数码产品的详细......