Semaphore 计数信号量限制资源访问的线程数目

目录

Semaphore 概述

常用方法

使用示例


Semaphore 概述

public class java.util.concurrent.Semaphore implements java.io.Serializable {

1、JDK1.5 提供的 Semaphone 计数信号量维护了一个许可证集,线程中调用 acquire() 方法从 Semaphone 中获取许可证,得到了许可证,Semaphone 的许可证数减1,线程继续向后运行,未得到许可证时,线程一直阻塞在 acquire()。

2、线程中获得许可执行完毕后,使用 release() 方法归还许可证到 Semaphone,Semaphone 的许可证数加1,此时其余阻塞在 acquire() 的线程便可以获取其它线程归还的许可证后继续执行。

3、Semaphore 只对可用许可的号码进行计数,并采取相应的行动,信号量常常用于多线程的代码中,限制访问某些资源(物理或逻辑的)的线程数目,比如数据库连接池。

Semaphore 计数信号量限制资源访问的线程数目

4、因为 Semaphone 的许可证数量是固定的,所以同一时刻最多只能有 Semaphone 许可证同等数量的线程访问,其余线程访问时必须等待已经拿到许可证的线程执行完毕(执行完毕的线程要归还许可证)。

常用方法

构造方法摘要
Semaphore(int permits)  创建具有给定的许可数和非公平的公平设置的 Semaphore
Semaphore(int permits, boolean fair) 创建具有给定的许可数和给定的公平设置的 Semaphore
方法摘要  
acquire()

从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断

获取一个许可(如果提供了一个)并立即返回,将可用的许可数减 1。

acquire(int permits)      

 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断

availablePermits() 返回此信号量中当前可用的许可数。
drainPermits()  获取并返回立即可用的所有许可。
release() 释放一个许可,将其返回给信号量。
release(int permits) 释放给定数目的许可,将其返回到信号量。
toString()   返回标识此信号量的字符串,以及信号量的状态。
tryAcquire(long timeout, TimeUnit unit) 如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。

使用示例

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;

public class Test {

    public static void main(String[] args) throws InterruptedException {
        //创建具有给定的许可数和非公平的公平设置的 Semaphore(计数信号量)
        Semaphore semaphore = new Semaphore(3);
        //使用线程池创建多个线程执行
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 6; i++) {
            executorService.execute(new MyThread(semaphore));//计数信号量作为参数传入
        }
    }
}

class MyThread extends Thread {
    private static Logger logger = Logger.getAnonymousLogger();//日志记录器
    private Semaphore semaphore;//计数信号量作为参数传入

    public MyThread(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            logger.info("线程 " + currentThread().getName() + " 准备获取许可证数,当前共有:" + semaphore.availablePermits());
            /**
             * acquire:从此计数信号量中获取一个许可证,在获得许可之前,此线程将一直阻塞,或者线程被中断。
             * 获取许可证后,semaphore 中可用的许可数减会 1
             */
            semaphore.acquire();
            logger.info("线程 " + currentThread().getName() + " 获得许可证,剩余许可证数:" + semaphore.availablePermits());
            Thread.sleep(2000 + new Random().nextInt(3000));//模拟线程在执行任务
            /**
             * release:当前线程释放许可证,将其返回给计数信号量
             * 释放许可证后,semaphore 中可用的许可数增加 1。如果任意线程试图获取许可,则选中一个线程并将刚刚释放的许可给予它。然后针对线程安排目的启用(或再启用)该线程。
             * 线程执行完成后一定要记得归还许可证,否则 Semaphore 的许可证用完之后,其它线程会一直阻塞在 acquire()
             */
            semaphore.release();
            logger.info("线程 " + currentThread().getName() + " 执行完毕,归还许可证,剩余许可证数:" + semaphore.availablePermits());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Semaphore 计数信号量限制资源访问的线程数目

完整输出内容如下:

三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 获得许可证,剩余许可证数:2
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 获得许可证,剩余许可证数:1
三月 11, 2019 4:34:51 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:51 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 执行完毕,归还许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:53 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:56 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 执行完毕,归还许可证,剩余许可证数:2
三月 11, 2019 4:34:57 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 执行完毕,归还许可证,剩余许可证数:3