控制并发线程数 - Semaphore

什么是Semaphore?

计数信号灯, Semaphore是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
信号量维护一组许可证,使用acquire()去获取许可证,在未获取到许可证之前会一直阻塞,直到获取到许可证,最后使用release() 释放许可证供其它线程获取。

理解

相信大家都有排队就餐的经验,商场里一家非常火爆的餐厅,两百人来就餐,但是餐厅只有100个位子,前面一百人先进去就餐,后边100人就在外面取号排队,餐厅里面一桌客人走后,后面排队的100人才能进去一人,以此类推,出来一人进去一人,许可证可以理解为就是手中的号,号还没到你你就一直等待,当餐厅走了一个人,空出来一个空位置后,刚好号到你了,你就可以进去了(例子不严谨,只作为理解使用)。

Semaphore构造方法

1、Semaphore(int permits)使用给定的许可数量和非公平性设置创建信号量。
2、Semaphore(int permits, boolean fair)使用给定的许可数量和给定的公平性设置创建一个信号量。
permits : 许可证-可用许可证的初始数量
fair : 设置是公平竞争还是非公平竞争,默认是使用非公平竞争,非公平竞争效率会比公平竞争效率高,因为非公平竞争会减少线程上下文切换,通过减少线程的切换来提高效率,设置为true为公平竞争。

Semaphore方法

类型 方法 描述
void acquire() 从这个信号量获取许可证,阻塞直到有一个可用,或者线程被中断
void acquire(int permits) 从这个信号量获取给定数量的许可证,阻塞直到所有许可证都可用,或者线程被中断
void acquireUninterruptibly() 从这个信号量获取许可证,阻塞直到有一个可用为止。
void acquireUninterruptibly(int permits) 从这个信号量获取给定数量的许可证,阻塞直到所有许可证都可用为止。
int availablePermits() 返回此信号量中当前可用的许可证数
int drainPermits() 获取并返回所有立即可用的许可证
protected Collection<Thread> getQueuedThreads() 返回包含可能正在等待获取的线程的集合
int getQueueLength() 返回等待获取的线程数的估计值
boolean hasQueuedThreads() 查询是否有线程正在等待获取
boolean isFair() 如果此信号量的公平性设置为true,则返回true
protected void reducePermits(int reduction) 减少可用许可证的数量
void release() 释放一个许可证,将其返回给信号量
void release(int permits) 释放给定数量的许可证,将它们返回给信号量
String toString() 返回标识此信号量及其状态的字符串
boolean tryAcquire() 从这个信号量获取许可证,只有在调用时有一个许可证可用时
boolean tryAcquire(int permits) 仅当调用时所有许可证都可用时,才从该信号量获取给定数量的许可证
boolean tryAcquire(int permits, long timeout, TimeUnit unit) 如果在给定的等待时间内所有许可证都可用,并且当前线程没有中断,则从该信号量获取给定数量的许可证
boolean tryAcquire(long timeout, TimeUnit unit) 如果在给定的等待时间内有一个可用,并且当前线程没有中断,则从该信号量获取许可

例子

package com.sy.thread.example;

import java.util.concurrent.Semaphore;

/**
 * Description: thread
 *
 * @author songyu
 */
public class SemaphoreTest1 {

    public static void main(String[] args) {
        //定义一个有2个许可证的信号量
        Semaphore semaphore = new Semaphore(2);
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取信号量,获取不到将阻塞,直到获取到许可证
                        semaphore.acquire();
                        System.out.println("线程"+Thread.currentThread().getName() + "获取到许可证,开始执行。。。。。。");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        //归还许可证
                        semaphore.release();
                        System.out.println("线程"+Thread.currentThread().getName() + "执行完毕,归还许可证");
                    }

                }
            }, String.valueOf(i)).start();
        }
    }

}

输出结果

线程0获取到许可证,开始执行。。。。。。
线程1获取到许可证,开始执行。。。。。。
线程0执行完毕,归还许可证
线程1执行完毕,归还许可证
线程3获取到许可证,开始执行。。。。。。
线程2获取到许可证,开始执行。。。。。。
线程2执行完毕,归还许可证
线程3执行完毕,归还许可证
线程4获取到许可证,开始执行。。。。。。
线程4执行完毕,归还许可证

通过执行结果可以看出,当2个许可证都被拿走后,其它来拿许可证的线程拿不到就一直被阻塞这,直到有的线程归还了许可证,阻塞中的线程抢到了许可证后才可以继续执行。

使用场景

限流

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。