Java随笔-Semaphore

Semaphore作为多线程同步工具,用于限制并发访问特定资源的线程数量,实现类似线程池的效果。它允许设定许可数量,线程通过acquire()获取许可,release()释放许可。在疫苗接种场景示例中,Semaphore限制了同时接种的人数,保证有序进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

原理
Semaphore(计数信号量)用来控制同时访问特定资源的线程数量,通过协调多线程,确保资源被合理使用。正常的锁在任何时刻都是只允许一个任务访问一项资源,而Semaphore允许多个任务同时访问一项资源。某些程度上和线程池有些相似,可用的数量固定,线程使用完后,剩下的进行排队,当有线程使用完毕后,放回线程池,然后再分配给排队的任务进行使用。
作用
Semaphore用来限制线程并发数量,用于限流,对访问的资源进行数量限制,比如:视频账号只允许最多两端同时在线,手机和电脑可以同时在线,若是想在平板上登录,手机和电脑中必须有一端退出登录才行;疫苗接种房间最多同时接种10人,接种者进入房间前发放许可证,只有手持许可证才能进入房间接种,10张许可证发放完后,剩下的人排队等着,接种完后收回许可证发放给后面排队的人进行接种。

主要方法描述

  1. public Semaphore(int permits)
    permits:获取许可线程的数量,默认是不公平的设置。
  2. public Semaphore(int permits, boolean fair)
    permits:获取许可线程的数量,fair:true表示线程启动顺序和获得许可的顺序,先启动的先获取,当然只是理论保证,实际中无法确保100%,false表示线程启动顺序和获得许可顺序无关,有些线程快,有些线程慢,每次都会不一样。
  3. acquire()
    获取许可,也就是消耗一个许可。
  4. acquire(int permits)
    每次调用消耗permits个许可。
  5. acquireUninterruptibly()
    消耗一个许可,不允许等待线程中断。
  6. acquireUninterruptibly(int permits)
    一次获取permits个许可,且等待线程不被中断。
  7. tryAcquire()
    尝试获取许可,并不阻塞线程,获取失败返回false。
  8. tryAcquire(long timeout, TimeUnit unit)
    指定时间内获取许可,没有获取成功只要在指定时间内就轮询获取,超时获取失败返回false,不阻塞线程。
  9. release()
    释放一个许可,并唤醒一个正在阻塞的线程。
  10. release(int permits)
    一次释放permits许可。
  11. availablePermits()
    获取可用许可数量。
  12. drainPermits()
    获取并返回所有可用许可,并将可用许可置为0。
  13. reducePermits(int reduction)
    减少可用许可数量,不阻塞线程。
  14. getQueueLength()
    返回正在等待获取许可的线程数量。
  15. hasQueuedThreads()
    查询是否还有正在等待获取许可的线程。

使用

        // 5张许可证
        final Semaphore semaphore = new Semaphore(5);
        // 使用线程池
        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            int finalI = i;
            Runnable runnable = () -> {
                try {
                    // 获取许可
                    semaphore.acquire();
                    System.out.println("第" + finalI + "位开始接种");
                    // 睡眠
                    Thread.sleep(new Random().nextInt(10000));
                    System.out.println("第" + finalI + "位接种完毕");
                    // 释放许可
                    semaphore.release();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();

结果:

0位开始接种
第1位开始接种
第2位开始接种
第3位开始接种
第4位开始接种
第3位接种完毕
第8位开始接种
第4位接种完毕
第5位开始接种
第1位接种完毕
第9位开始接种
第8位接种完毕
第7位开始接种
第5位接种完毕
第6位开始接种
第7位接种完毕
第0位接种完毕
第2位接种完毕
第6位接种完毕
第9位接种完毕

观察结果发现,0、1,2、3、4满5位后就没有开始接种的,只有第3位接种完毕后,空出一个位置,这个位置给了第8位,第4位接种完毕后空位给了第5位,第1位接种完毕后空出的位置给了第9位,总而言之,就是空出一位顶上一位,直到所有人接种完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值