Java中Semaphore信号量的方法解析

 更新时间:2023年12月27日 08:36:59   作者:缘来如此09  
这篇文章主要介绍了Java中Semaphore信号量的方法解析,  Semaphore信号量是用来控制同 时访问 特定 资 源的 线 程数量,它通 过协调 各个 线 程,以保证合理的使用公共 资源,需要的朋友可以参考下

一、简介

Semaphore(信号量)是用来控制同 时访问 特定 资 源的 线 程数量,它通 过协调 各个 线 程,以 保 证 合理的使用公共 资源。实现其实就是一个共享锁,是基于AQS实现的,通过state变量来实现共享。通过调用acquire方法,对state值减去一,当调用release的时候,对state值加一。当state变量小于0的时候,在AQS队列中阻塞等待

二、使用场景

当我们需要对某个任务限制资源使用时,比如我们这个系统 有多个接口,其中一个接口不重要其他接口特别重要,这时候就可以通过信号量限制这个接口可使用的线程数量防止再一些特殊情况这个接口使用超量的线程资源从而影响到重要任务的执行

三、构造方法

Semaphore可以实现公平和非公平

  public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

其中NonfairSync和FairSync都是继承自Sync,而Sync继承于AQS所以Semaphore就是通过AQS实现的

abstract static class Sync extends AbstractQueuedSynchronizer {
    Sync(int permits) {
        setState(permits);
    }
}

从这里可以看出来调用了AQS的setState方法,读过前面的文章应该明白AQS的核心就是内部维护着一个volatile修饰的同步状态值state。所以说当我们new Semaphore(10)时候,实际上是在AQS的框架中初始化了一个同步状态为10的值。

四、acquire方法

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);
}
protected int tryAcquireShared(int acquires) {
    return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

通过源代码我们发现此处semphore处理获取锁的业务逻辑是:

  1. 获取同步状态值
  2. 每个线程进来就减去请求的值,此处请求的值是1.然后用可用同步状态值减去请求的值得到同步状态剩余的值。
  3. 如果请求的值大于可用的值或者CAS操作把可用值改为剩余可用的值那么就返回剩下可用的值。

五、release()释放锁

Semaphore semaphore=new Semaphore(10);
semaphore.release();
public void release() {
    sync.releaseShared(1);
}

此处sync调用了AQS中的方法releaseShared,在这个方法中如果释放成功那么就调用doReleaseShared方法,此方法在前面AQS共享模式文章中已经讲解过,此处不在详细讲解。它主要作用就是释放队列中的节点。

六、整体流程

附上网图

七、实例代码

  public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        Semaphore semaphore = new Semaphore(5);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        for (int i = 0; i < 20; i++) {
            threadPoolExecutor.execute(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "开始执行");
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + "执行成功############");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

输出:

可以看出最多只有五个线程在执行

到此这篇关于Java中Semaphore信号量的方法解析的文章就介绍到这了,更多相关Semaphore信号量的方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 什么是Spring Boot

    什么是Spring Boot

    Spring是一个非常受欢迎的Java框架,它用于构建web和企业应用。本文介绍将各种Spring的配置方式,帮助您了解配置Spring应用的复杂性
    2017-08-08
  • IntelliJ IDEA 2021.1 EAP 4 发布:字体粗细可调整Git commit template 支持

    IntelliJ IDEA 2021.1 EAP 4 发布:字体粗细可调整Git commit template 支持

    这篇文章主要介绍了IntelliJ IDEA 2021.1 EAP 4 发布:字体粗细可调整,Git commit template 支持,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • intellij idea使用git stash暂存一次提交的操作

    intellij idea使用git stash暂存一次提交的操作

    这篇文章主要介绍了intellij idea使用git stash暂存一次提交的操作,具有很好的参考价值希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 解决Properties属性文件中的值有等号和换行的小问题

    解决Properties属性文件中的值有等号和换行的小问题

    这篇文章主要介绍了解决Properties属性文件中的值有等号有换行的小问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java基础之toString的序列化 匿名对象 复杂度精解

    Java基础之toString的序列化 匿名对象 复杂度精解

    序列化即为把内存中的对象转换为字节写入文件或通过网络传输到远端服务器,本章节将带你了解Java toString的序列化 匿名对象 复杂度,需要的朋友可以参考下
    2021-09-09
  • 一篇文章带你入门Java接口

    一篇文章带你入门Java接口

    这篇文章主要介绍了JAVA中接口的定义和接口的实现,文中讲解非常细致,配合代码更好的帮大家学习参考,感兴趣的朋友可以了解下
    2021-08-08
  • 详解spring cloud如何使用spring-test进行单元测试

    详解spring cloud如何使用spring-test进行单元测试

    这篇文章主要介绍了spring cloud如何使用spring-test进行单元测试,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Java数组扩容实现方法解析

    Java数组扩容实现方法解析

    这篇文章主要介绍了Java数组扩容实现方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 带你盘点Java的五种运算符

    带你盘点Java的五种运算符

    这篇文章主要介绍了Java基本数据类型和运算符,结合实例形式详细分析了java基本数据类型、数据类型转换、算术运算符、逻辑运算符等相关原理与操作技巧,需要的朋友可以参考下
    2021-07-07
  • Java毕业设计实战之工作管理系统的实现

    Java毕业设计实战之工作管理系统的实现

    这是一个使用了java+SSM+Jsp+Mysql开发的工作干活管理系统,是一个毕业设计的实战练习,具有管理系统该有的所有功能,感兴趣的朋友快来看看吧
    2022-02-02

最新评论