借助Semaphore特性 实现限流器、对象池

115 阅读1分钟

Semaphore

一个计数器、一个等待队列、三个方法

image-20210701210759509

  • init对应创建对象时初始化信号量new Semaphore(size),计数器的值就是限制进入临界资源的线程数;
  • down对应semaphore.acquire()方法获取进入临界资源资格,计数器减一;
  • up对应semaphore.release()方法,操作完临界资源,释放信号量,计数器加一;

执行流程:

  • 线程获取到信号量->进入临界区域执行->执行完释放信号量;
  • 线程获取信号量失败,计数器值为0->线程被阻塞,直到有线程释放信号量,唤醒阻塞线程;

特性:允许多个线程进入临界区

借助这个特性实现各种资源池、限流器

对象池实现:

/**
 * 对象池
 * @author zhan
 * @version 2021/6/27
 */
public class ObPool<T, R> {
    private final List<T> pool;
    private final Semaphore semaphore;

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

    public R exec(Function<T, R> func) throws InterruptedException {
        T t = null;
        semaphore.acquire();
        try {
            T remove = pool.remove(0);
            if (remove == null){
                throw new RuntimeException("empty pool!");
                // 或者再次填充对象池
            }
            return func.apply(remove);
        }finally {
            semaphore.release();
            pool.add(t);
        }
    }

    @Override
    public String toString(){
        return pool.toString()+"\nsemaphore\navailablePermits:"+semaphore.availablePermits()+"drainPermits:"+semaphore.drainPermits()+"QueueLength:"+semaphore.getQueueLength();
    }
}