JAVA并发包之使用Semaphore实现一个限流器

181 阅读2分钟

前段时间看了写并发编程相关的一些文章,感觉收益颇多,赶紧记录下来。虽然工作中很少能接触到这样的场景,但是学习的脚步不能停下来! Come on !

信号量模型可以简单理解为三个操作:一个计数器、一个等待队列、三个方法。在信号量模型里。计数器和等待队列对外是透明的,所以只能通过信号量模型提供的三个方法来访问他们。这三个方法可以理解为: init()、down()、up()。 可以通过一张图片看一下。

这三个方法语义的解释:

​ init(): 设置计数器的初始值
​ down(): 计数器的值减1;如果此时计数器的值小于0,则当前线程被阻塞,否则当前线程可以继续执行。
​ up(): 计数器的值加1;如果此时计数器的值小于或者等于0,则唤醒等待队列中的一个线程,并将其从等待队列中移除。

这三个方法都是原子性的,并且都是由信号量模型方法实现保证的。java中的对应的类为Semaphore。 个人理解Semaphore有两个核心的方法:

​acquire():获取一个许可,标识该线程可以执行(对应的前面说到的init()方法)。 ​release(): 归还一个许可(对应前面说到的down()方法)。

用Semaphore实现一个简单限流器:
场景:创建一个对象池,一次性创建N个对象,之后所有的线程重复利用这N个对象,当然对象被释放前,也是不允许其他线程使用的。代码如下:

/**
 * @Description: 对象池,只允许 size个数量线程同时使用对象,可以重复使用对象。可以达到限流效果
 * @author: ListenerSun(男, 未婚) 微信:810548252
 * @Date: Created in 2019-12-09 23:23
 */
public class ObjectPool<T,R> {

    /**
     *对象集合
     */
    final List<T> pool;
    /**
     * 信号量 控制 同时使用对象 的线程个数
     */
    final Semaphore sem;

    public ObjectPool(int size,T t) {
        pool = new Vector<>();
        for(int i = 0; i < size; i++){
            pool.add(t);
        }
        sem = new Semaphore(size);
    }

    R excute(Function<T,R> function) throws InterruptedException {
        T t = null;
        sem.acquire();
        try{
            t = pool.remove(0);
            return  function.apply(t);
        }finally {
            pool.add(t);
            sem.release();
        }
    }
}