并发工具 Semaphore

定义

Semaphore :信号量,并发控制中用于控制某个资源同时被访问的个数。例如程序中某个方法执行耗时长,所需资源量大。可以通过Semaphore控制同一时刻访问该方法的线程数。

应用场景

主要用于流量控制,特别是公共资源有限的的应用场景(数据库连接)或者一些慢服务

主要方法

  1. public Semaphore(int permits) :构造函数一,permits为信号量许可证的大小;
  2. public Semaphore(int permits, boolean fair) :构造函数二:fair为是否设置公平策略参数,如果为true,申请许可证的等待线程会进入FIFO队列中。若为false,允许等待的线程有插队的可能。
  3. public void acquire():以阻塞的方式获取一个申请许可证,在有可用的许可证时候就返回许可;如果没有可用的许可则阻塞等待,直至获取到许可;
  4. public void acquire(int permits):同时获取permits个许可;
  5. public void release():释放一个许可;
  6. public void acquire(int permits):释放permits个许可;
  7. public boolean tryAcquire():尝试获取许可证,如果当前没有可用的许可证,申请的线程不需要进入阻塞,而是继续往下执行;
  8. public boolean tryAcquire(long timeout, TimeUnit unit) :带有超时时间去获取蓄许可证。例如“5秒钟内还是获取不到许可证,我就继续往下执行,干自己的事!”
  9. public int availablePermits():查询可用的许可;

例子


package com.mark.learning.concurrent2.flowcontrol.semaphore;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @Description: 演示Semaphore用法
 * @Author: Mark
 * @CreateDate: 2020/2/3 14:15
 * @Version: 1.0
 * @Copyright : 豆浆油条个人非正式工作室
 */
@Slf4j
class Task implements Runnable{

    private static final Semaphore SEMAPHORE = new Semaphore(3,true);

    @Override
    public void run() {
        //获取信号量许可证
        try {
            SEMAPHORE.acquire();
            log.info(Thread.currentThread().getName()+"获取到了 信号量许可证");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //模拟 耗时长的程序
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //释放信号量
        SEMAPHORE.release();
        log.info(Thread.currentThread().getName()+"释放了 信号量许可证");
    }
}

public class SemaphoreDemo1 {
    private static ExecutorService executorService = Executors.newFixedThreadPool(5);

    public static void main(String[] args) {
        //运行十个线程
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Task());
        }
        executorService.shutdown();
    }
}

运行结果

16:39:57.795 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:39:57.795 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2获取到了 信号量许可证
16:39:57.795 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5获取到了 信号量许可证
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证
16:40:02.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3获取到了 信号量许可证
16:40:02.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4获取到了 信号量许可证
16:40:02.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5释放了 信号量许可证
16:40:02.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2释放了 信号量许可证
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4释放了 信号量许可证
16:40:07.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证
16:40:07.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3释放了 信号量许可证
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4获取到了 信号量许可证
16:40:07.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5获取到了 信号量许可证
16:40:07.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2获取到了 信号量许可证
16:40:12.802 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2释放了 信号量许可证
16:40:12.802 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1获取到了 信号量许可证
16:40:12.802 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5释放了 信号量许可证
16:40:12.802 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4释放了 信号量许可证
16:40:17.803 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1释放了 信号量许可证

通过分析log的打印时间,每次最多只能允许3个线程同时执行。

注意点

  • 一次获取可获取和释放多个许可证。
 semaphore.acquire(3);//一次获取三个许可
 semaphore.release(3);//一次释放三个许可
  • 获取许可和释放许可的数量需要保持一致;
  • 释放许可不一定由获取的许可来完成。例如线程A获取了许可,也可以由线程B来释放许可
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章