JUC-7.1-线程协作-Semaphore

Semaphore 信号量,也是一个线程协作的工具,可以用来限制或管理数量有限的资源的使用

用法

信号量的作用是维护一个 “许可证” 的计数,线程可以获取许可证,然后信号量剩余许可证数量减一,当信号量所拥有的许可证为0的时候,下一个想要获取许可证的线程就需要等待,直到有另外的线程释放了许可证

常用的几个方法如下

  • 构造函数: 和上文的 CountDownLatch 一样, Semaphore 在初始化的时候也需要指定许可证的数量,还有一个构造参数是配置公平策略,如果是 true ,当有了新的许可证的时候,会把它给等待时间最长的线程
  • acquire()/acquireUninterruptibly(): 这两个方法是用来获取许可证的,从名字上来看就知道,后面的是可以在获取的过程种被打断的
  • tryAcquire(timeout)/tryAcquire(): 这两个方法是尝试获取许可证,在规定时间内立即返回,不会阻塞
  • release(): 释放许可证

使用案例

用个具体的代码演示以下信号量的使用

@Slf4j
public class SemaphoreTest {
    static Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new Task()).start();
        }
    }

    @Slf4j
    static class Task implements Runnable{

        @Override
        public void run() {
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("获取到了许可证,执行具体逻辑...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("完成任务,释放许可证...");
            semaphore.release();
        }
    }
}

新建一个3个许可证的信号量,然后新建 100 个线程都去获取证书,执行后再释放掉,看一下控制台输出

11:03:17.556 [Thread-1] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:17.556 [Thread-0] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:17.556 [Thread-2] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:18.579 [Thread-0] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:18.579 [Thread-2] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:18.579 [Thread-1] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:18.579 [Thread-4] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:18.579 [Thread-5] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:18.579 [Thread-3] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:19.579 [Thread-3] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:19.579 [Thread-5] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:19.579 [Thread-4] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:19.579 [Thread-6] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:19.579 [Thread-7] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:19.579 [Thread-29] INFO com.learning.java.cooperation.SemaphoreTest$Task - 获取到了许可证,执行具体逻辑...
11:03:20.579 [Thread-6] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:20.579 [Thread-7] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...
11:03:20.579 [Thread-29] INFO com.learning.java.cooperation.SemaphoreTest$Task - 完成任务,释放许可证...

可以看到每次执行的都是3个线程,释放之后才会有下一批线程获取到,这里上面构造函数中没有设置为公平的,所以这里获取到许可证的线程并不是按顺序的

注意点

  1. acquire()release() 方法都有一个重载的方法,可以传入一个 int 类型的参数,表示获取/释放几个许可证,但是并不强制获取几个就得释放几个,比如获取两个释放一个也是可以的,但最后许可证会越来越少,会导致程序卡死
  2. 初始化的时候一般设置为公平的,更加合理
  3. 并不是必须由获取许可证的线程释放许可证, 比如A线程获取了许可证,可以由B线程释放
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值