首页 > 编程语言 >「java.util.concurrent并发包」之 Semaphore

「java.util.concurrent并发包」之 Semaphore

时间:2024-02-29 10:46:29浏览次数:25  
标签:许可 队列 阻塞 util concurrent static 线程 Semaphore 发包

一 Semaphore是什么

Semaphore也叫信号量,在JDK1.5被引入,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。

Semaphore内部维护了一组虚拟的许可,许可的数量可以通过构造函数的参数指定。

  • 访问特定资源前,必须使用acquire方法获得许可,如果许可数量为0,该线程则一直阻塞,直到有可用许可。
  • 访问资源后,使用release释放许可。

Semaphore和ReentrantLock类似,获取许可有公平策略和非公平许可策略,默认情况下使用非公平策略。

 

 

二 应用场景

Semaphore可以用来做流量分流,特别是对公共资源有限的场景,比如数据库连接。
假设有这个的需求,读取几万个文件的数据到数据库中,由于文件读取是IO密集型任务,可以启动几十个线程并发读取,但是数据库连接数只有10个,这时就必须控制最多只有10个线程能够拿到数据库连接进行操作。这个时候,就可以使用Semaphore做流量控制。

public class SemaphoreTest {
    private static final int COUNT = 40;
    private static Executor executor = Executors.newFixedThreadPool(COUNT);
    private static Semaphore semaphore = new Semaphore(10);
    public static void main(String[] args) {
        for (int i=0; i< COUNT; i++) {
            executor.execute(new ThreadTest.Task());
        }
    }

    static class Task implements Runnable {
        @Override
        public void run() {
            try {
                //读取文件操作
                semaphore.acquire();
                // 存数据过程
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}

 

实现原理

本文代码源于JDK1.8
Semaphore实现主要基于java同步器AQS,不熟悉的可以移步这里 深入浅出java同步器

内部使用state表示许可数量。

 

无参和有参带有permits许可数的方法底层均调用acquireSharedInterruptibly

 

 

非公平锁实现

acquires值默认为1,表示尝试获取1个许可,remaining代表剩余的许可数。

  • 如果remaining < 0,表示目前没有剩余的许可。
  • 当前线程进入AQS中的doAcquireSharedInterruptibly方法等待可用许可并挂起,直到被唤醒。
 

也许有人会有疑问,非公平性体现在哪里?
当一个线程A执行acquire方法时,会直接尝试获取许可,而不管同一时刻阻塞队列中是否有线程也在等待许可,如果恰好有线程C执行release释放许可,并唤醒阻塞队列中第一个等待的线程B,这个时候,线程A和线程B是共同竞争可用许可,不公平性就是这么体现出来的,线程A一点时间都没等待就和线程B同等对待。

 

 

公平锁实现

可以看到和非公平策略相比,就多了一个对阻塞队列的检查。

  • 如果阻塞队列没有等待的线程,则参与许可的竞争。
  • 否则直接插入到阻塞队列尾节点并挂起,等待被唤醒。

 

 

releases值默认为1,表示尝试释放1个许可,next 代表如果许可释放成功,可用许可的数量。

  • 通过unsafe.compareAndSwapInt修改state的值,确保同一时刻只有一个线程可以释放成功。
  • 许可释放成功,当前线程进入到AQS的doReleaseShared方法,唤醒队列中等待许可的线程。

标签:许可,队列,阻塞,util,concurrent,static,线程,Semaphore,发包
From: https://www.cnblogs.com/balfish/p/18042908

相关文章

  • 使用fsutil创建指定大小文件
    以下命令将在 D:\projects\test目录下创建大小为4KB的文件 4096.txtfsutilfilecreatenewD:\projects\test\4096.txt4096需要注意的是,通过fsutil指令生成的文件是空文件。指定内容生成指定大小文件以下命令将在D:\projects\test目录下创建大小为2KB的文件2k......
  • 都说了别用BeanUtils.copyProperties,这不翻车了吧
    分享是最有效的学习方式。博客:https://blog.ktdaddy.com/故事新年新气象,小猫也是踏上了新年新征程,自从小猫按照老猫给的建议【系统梳理大法】完完整整地梳理完毕系统之后,小猫对整个系统的把控可谓又是上到可一个新的高度。开工一周,事情还不是很多,寥寥几个需求,小猫分分钟搞定......
  • Python使用shutil模块操作文件/文件夹
    Python的标准库中os模块已经可以操作文件了,但是具有很多局限性(比如不能复制文件),因此Python的另一个标准库shutil对文件/文件夹的移动,复制,删除文件夹,压缩,解压等操作做了增强,更加方便用户进行使用。 1、复制文件/文件夹(shutil.copy(src,dst))1.1复制文件复制文件常......
  • PDFUtils (解析PDF 中的文本 和 图片 PDF 转 HTML HTML 转 PDF)
    引入pdfbox依赖<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.19</version></dependency>packagecom.icil.swif......
  • go psutil获取磁盘信息
    示例代码://通过psutil获取所有分区的信息//重要字段:/*fmt.Printf("Device:%s\n",partition.Device)fmt.Printf("Mountpoint:%s\n",partition.Mountpoint)fmt.Printf("Filesystemtype:%s\n",partition.Fstype)fmt.Printf(......
  • UtilMeta - 简洁高效的 Python 后端元框架
    最近开源了我开发多年的一个Python后端框架:UtilMeta项目介绍UtilMeta是一个用于开发API服务的后端元框架,基于Python类型注解标准高效构建声明式接口与ORM查询,能够自动解析请求参数与生成OpenAPI文档,高效开发RESTful接口,产出的代码简洁清晰,并且支持使用主流Python......
  • Go - concurrent processing is not always faster than sequential processing
      ......
  • JetCacheUtil 删除本地及远端缓存
    publicclassJetCacheUtil{privateJetCacheUtil(){}/***删除缓存**/publicstaticbooleanremoveCache(CacheLocatecacheLocate){Assert.isTrue(StringUtils.hasText(cacheLocate.getCacheKey())&&StringUtils.hasT......
  • java.util.Optional 是 Java 8 引入的一个类,用于处理可能为 null 的值。它可以避免 Nu
    可以使用 Optional 来包装可能为 null 的值,然后通过一系列方法来处理这个值,例如 isPresent() 检查是否有值,orElse() 获取值或默认值,map() 对值进行转换等。这样可以更安全地处理可能为 null 的情况。 importjava.util.Optional;publicclassOptionalExample{  ......
  • StringUtils使用与源码分析
    在apache的lang3包中有个StringUtils工具类,该工具类为开发中常用的字符串处理工具类 非空判断,isBlank和isEmpty这俩方法的形参都是charSequence字符序列。isEmpty判断这个字符序列是否为null,还有长度是否为0,如果是,则返回true,反之返回falseisBlank在isEmpty之上还有一个,如果长度......