`
suichangkele
  • 浏览: 201466 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

juc - Semaphore源码解读

    博客分类:
  • java
阅读更多

Semaphore,翻译叫做信号灯,是用来做资源访问限制的,他维持了一个准许指令的集合,如果当前没有可以指令的话,调用一次acquire就会将当前的线程阻塞,没调用一次release就会将当前线程持有的指令还回指令集合。他的内部实现跟CountDownLatch类似,也是直接使用的aqs,在创建的时候就会设定一个state标记,用来表示可以同时被使用准许指令的最大值,在某个线程调用acquire的时候先判断这个值大于0,如果是的话表示当前可以获得一个准许,否则说明当前的指令已经全部用完,当前的线程被挂起,进入aqs的队列中。当某个已经获得指令的线程调用release的时候要把获取的指令返还,也就是将state标记增大。大体了解了意思之后,还是看看他的源码吧:

1、构造方法:

public Semaphore(int permits, boolean fair) {//第一个参数表示可以同时被获取的指令的个数,第二个参数表示在获取指令的时候是否是公平的,这个和ReentrantLock的公平的参数是一样的,如果是公平的,则任何获取操作都会先判断当前的aqs的队列中是否有等待的线程,如果有则排在最后面,如果是不公平的,则直接获取
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);//无论是fair还是不fair的都是aqs的子类,permits最终会被设置为state标记的大小。这里我以非公平的aqs为例。
    }

 2、获取锁的方法,这个是会抛异常的,即如果线程被挂起,其他线程调用了这个线程的interrupt方法,就会抛InterruptedException异常。

 public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//调用aqs的获取方法,这个方法都是直接调用的aqs的方法,先判断是否可以获取,即tryAcquireShared方法,如果返回正数表示可以获取锁,否则排队等待。我们看一下非公平的aqs的代码
    }

 

 final int nonfairTryAcquireShared(int acquires) {//要获取的指令的数量
            for (;;) {
                int available = getState();//当前的标记
                int remaining = available - acquires;//最终返回的就是这个值,如果要获取的值小于state,则表示获得指令,否则没有获得指令。
                if (remaining < 0 || compareAndSetState(available, remaining))//如果小于0的话则直接返回,表示获取失败,第二个compareXXX是cas更新state的值。
                    return remaining;
            }
        }

 经过前面的博客的介绍,尤其是ReentrantLock和CountDownLatch,如果返回的是小于0的,就会加入到队列中,这里就不再重复贴代码了。返回的正负值的判断是根据当前的state的值和acquire的大小判断的。

 

3、获取所得方法,这个不会抛异常,

public void acquireUninterruptibly() {
    sync.acquireShared(1);//不抛异常的阻塞
}

 4、一次获取多个指令的方法

public void acquire(int permits) throws InterruptedException {
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireSharedInterruptibly(permits);//他的思路和上面还是一样的,只不过将state减小的值更大一些,不再是1.
}

 acquire的方法基本原理都是一样的,在获取不到的时候就会排队,这个类没有限定时间的排队等待。

 

5、尝试性的获取指令,有好多个,都是tryAcquire开头的,有带有超时时间的,有的带有要获取的指令的个数,他的思路和ReentrantLock中的aqs是一样的,这里只写一个

public boolean tryAcquire() {
    return sync.nonfairTryAcquireShared(1) >= 0;//判断当前的state标记的值是否大于1,如果是则获得指令并返回true,否则不获取指令也不排队,直接返回false。nonfairTryAcquireShared方法在上面介绍过了,
}

6、释放锁的方法;release方法,有的是释放一个,有的是多个指令。最终调用的是aqs的如下方法:

protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();//当前的state
                int next = current + releases;//
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))//cas设置state,这个方法只会返回true,不会返回false。
                    return true;
            }
        }
从这个方法来看,是可以release的指令的数量多余获取的指令的数量,在方法里面并没有判断的地方。

 在成功的返回true只会,这个方法还会调用doReleaseShared方法,很容易就能明白,他是为了唤醒因为获取不到指令而park的线程,这个队列是shared,即一下唤醒所有的阻塞的线程,但是由于state的大小的限制,很多的线程由于没有获取指令又一次被park了,这一点和CountDownLatch的思路一样。

7、获得当前剩余的指令的数量:

 public int availablePermits() {
        return sync.getPermits();//里面就是调用的获取state的方法,查看state的值。
    }

 

8、将当前的指令全部取消

public int drainPermits() {
    return sync.drainPermits();//drain有使...干涸的意思,即将当前剩余的所有的指令全部取消。
 }

 sync的drainPermits方法:

final int drainPermits() {
   for (;;) {
       int current = getState();//当前的state
       if (current == 0 || compareAndSetState(current, 0))//如果当前的state是0,直接返回,如果不是0,则通过cas设置为0,这样就没有可以获取的指令的了
           return current;
   }
}

 通过这个方法以及上面的release方法,可以发现Semaphore并没有严格的限制获取的指令必须归还,比如release中就可以归还大量的指令,也可以通过上面的drainPermtis将所有的指令全部取消,也就是这个指令的数量是可以动态改变的。

 

就这么简单,又学了一个juc的常用类。

 

分享到:
评论

相关推荐

    tuling-juc-final.zip

    本项目"tuling-juc-final.zip"显然聚焦于Java并发编程的实践,通过一系列代码示例来演示和解释Java内存模型(JMM)、`synchronized`关键字以及`volatile`关键字的使用。下面我们将深入探讨这些核心概念。 Java内存...

    java - juc - 多线程 - 学习 -思维导图

    java - juc - 多线程 - 学习 -思维导图

    Java-JUC-多线程 进阶

    Java-JUC-多线程进阶 Java-JUC-多线程进阶resources是 Java 并发编程的高级课程,涵盖了 Java 中的并发编程概念、线程安全、锁机制、集合类、线程池、函数式接口、Stream流式计算等多个方面。 什么是JUC JUC...

    heima-JUC-资料

    8. **线程通信**:`Semaphore`(信号量)、`CountDownLatch`(倒计时器)、`CyclicBarrier`(循环栅栏)和`Phaser`(屏障)等工具类,用于控制线程间的同步和通信,实现特定的并发模式。 9. **Fork/Join框架**:...

    个人学习-JUC-笔记

    - **CountDownLatch/CyclicBarrier/Semaphore**:信号量类,用于控制并发线程数量或同步点。 8. **FutureTask** - **FutureTask**:表示一个异步计算的结果,它可以被取消,查询是否完成,获取或检查结果。 9. *...

    Java 多线程与并发(7-26)-JUC - 类汇总和学习指南.pdf

    "Java 多线程与并发(7-26)-JUC - 类汇总和学习指南" Java 多线程与并发是 Java 编程语言中的一部分,用于处理多线程和并发编程。Java 提供了一个名为 JUC(Java Utilities for Concurrency)的框架,用于帮助开发者...

    A-JUC-JVM-Java并发知识..pdf

    JUC的同步器包括CountDownLatch、CyclicBarrier、Semaphore等,它们是为了解决多个线程协作完成特定任务的工具。例如,CountDownLatch可以让一些线程等待其他线程完成操作后再继续执行,而CyclicBarrier则让一组线程...

    juc-study编程笔记.md

    学习狂神说的juc编程的笔记

    juc-jenkins-2018:JUC Jenkins 2018演示源代码

    juc-jenkins-2018 JUC Jenkins 2018演示源代码 先决条件 为了运行此演示,必须有一个有效的JDK,git命令以及curl。 克隆存储库 将此存储库克隆到您家中的某个位置: git clone ...

    juc-1(2).docx

    【JUC 概念】 Java Util Concurrency (JUC) 是 Java SDK 中的一个核心包,位于 `java.util.concurrent` 下,它提供了丰富的线程同步和并发工具类,旨在简化多线程编程,提高程序的并发性能。JUC 包含了线程池、并发...

    juc_nio_linux.rar

    在Java中,`java.util.concurrent`包包含了大量并发控制和并行计算的类与接口,如ExecutorService、Semaphore、CountDownLatch等,它们使得开发者能够更容易地编写出高性能、多线程的程序。 NIO(New Input/Output...

    JUC-3 微程序控制计算机系列实验资源

    微程序控制器实验1. 连接好实验线路,检查无误后接通电源。2. 将编程开关(MJ20)置为PROM(编程)状态。3. 将STATE UNIT中的STEP置为“STEP”状态,STOP置为“RUN”状态。4. 在UA5-UA0开关上置要写的某个微地址(八进制)...

    juc-learn:juc相关源码的分析以及使用介绍

    本项目"juc-learn"专注于JUC相关源码的分析和使用介绍,旨在帮助开发者深入理解并熟练运用这些并发工具。 1. **并发基础** 在Java中,多线程是并发编程的基础。通过创建Thread对象或实现Runnable接口,我们可以...

    java并发编程专题(六)----浅析(JUC)Semaphore

    Java 并发编程专题(六)----浅析(JUC)Semaphore Java 并发编程专题(六)----浅析(JUC)Semaphore 是 Java 并发编程中的一种重要机制,它主要用于控制多个线程访问共享资源的同时性。Semaphore 是一种信号量...

    JUC-master

    《JUC:Java并发编程的艺术》 在Java世界中,JUC(Java Util Concurrency)是并发编程的核心库,它提供了丰富的...通过深入学习JUC-master项目,我们可以更深入地理解Java并发编程的原理和实践,提升我们的编程技能。

    juc-demo:JUC包下常用工具练习Demo

    juc-demo JUC包下常用工具练习Demo 内容: 1、Semaphore 2、CountDownLatch 3、CyclicBarrier 4、ReentrantLock + Condition实现阻塞队列 Created by @minghui.y.

    免费开源!!主要是Java技术栈的文章

    1、Java并发体系-第一阶段-多线程基础知识 2、Java并发体系-第二阶段-锁与同步-[1] 3、Java并发体系-第二阶段-锁与同步-[2] 4、Java并发体系-第二阶段-锁与同步-[3] ...7、Java并发体系-第四阶段-AQS源码解读-[1]

    JUC线程高级

    JUC线程高级,

    JUC并发编程与源码分析视频课.zip

    《JUC并发编程与源码分析视频课》是一门深入探讨Java并发编程的课程,主要聚焦于Java Util Concurrency(JUC)库的使用和源码解析。JUC是Java平台提供的一组高级并发工具包,它极大地简化了多线程编程,并提供了更...

    22 尚硅谷Java JUC线程高级视频

    教程视频:在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类, 用于定义类似于线程的自定义子系统,包括线程池,异步 IO 和轻量级任务框架;还提供了设计用于多线程上下文...

Global site tag (gtag.js) - Google Analytics