`
suichangkele
  • 浏览: 197931 次
  • 性别: 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-多线程进阶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-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 和轻量级任务框架;还提供了设计用于多线程上下文...

    JUC+课程源码+线程操作

    本课程资源主要围绕JUC进行展开,通过样例源码帮助学习者深入理解和掌握线程操作的相关知识。 在JUC中,核心组件包括`ExecutorService`、`Semaphore`、`CountDownLatch`、`CyclicBarrier`、`Future`、`...

    江苏大学计组课设指令编写

    江苏大学计组课设指令编写是计算机组成原理课程设计报告的一部分,该报告的主要内容是设计和实现 JUC2 模型机的微程序。下面是该报告的详细知识点解释: 1. 目标要求 计算机组成原理课程设计的目标是设计和实现一...

Global site tag (gtag.js) - Google Analytics