第二部分:并发工具类16->Semaphore:如何快速实现一个限流器

1.Semaphore

信号量,类比红绿灯

编程中,线程能不能执行,看信号量是否允许

2.信号量模型

计数器+等待队列+三个方法

计数器和等待队列对外是透明的,只能通过提供的三个方法(init,down,up)来访问它们

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

init,down,up三个方法都是原子性的,通过信号量模型实现方保证
java.util.concurrent.Semaphore实现

信号量模型


class Semaphore{
  // 计数器
  int count;
  // 等待队列
  Queue queue;
  // 初始化操作
  Semaphore(int c){
    this.count=c;
  }
  // 
  void down(){
    this.count--;
    if(this.count<0){
      //将当前线程插入等待队列
      //阻塞当前线程
    }
  }
  void up(){
    this.count++;
    if(this.count<=0) {
      //移除等待队列中的某个线程T
      //唤醒线程T
    }
  }
}

sdk并发包里,down和up对应的是acquire和release

3.如何用信号量

count += 1,临界区,只允许一个线程执行,

类似互斥锁,进入临界区之前执行down操作,退出临界时执行up操作


static int count;
//初始化信号量
static final Semaphore s 
    = new Semaphore(1);
//用信号量保证互斥    
static void addOne() {
  s.acquire();
  try {
    count+=1;
  } finally {
    s.release();
  }
}

多线程T1,T2,同时调用acquire时,acquire是原子操作,只有一个线程能将信号量的计数器变为0,线程T2将计数器减为-1
对于线程T1,信号量里面计数器值是0,大于等于0,线程T1会继续执行,执行count += 1。
对于线程T2,信号量里面计数器值是-1,小于0,按照信号量模型描述,T2线程被阻塞。
T1执行完count+=1操作有,执行release()操作,信号量计数器值加1,变为0,小于等于0,对应信号量模型up描述,T2线程被唤醒,T2在T1执行完代码后获取了执行临界区的机会,保证了互斥性

4.快速实现限流器

sdk里面有互斥锁了,干嘛还用semaphore呢
sempahore可以允许多个线程访问一个临界区

限流:不允许多与N个线程同时进入临界区

信号量计数器,设置为1,表示只允许一个线程进入临界区,设置为n,表示同时允许n个线程进入临界区

对象池的伪代码


class ObjPool<T, R> {
  final List<T> pool;
  // 用信号量实现限流器
  final Semaphore sem;
  // 构造函数
  ObjPool(int size, T t){
    pool = new Vector<T>(){};
    for(int i=0; i<size; i++){
      pool.add(t);
    }
    sem = new Semaphore(size);
  }
  // 利用对象池的对象,调用func
  R exec(Function<T,R> func) {
    T t = null;
    sem.acquire();
    try {
      t = pool.remove(0);
      return func.apply(t);
    } finally {
      pool.add(t);
      sem.release();
    }
  }
}
// 创建对象池
ObjPool<Long, String> pool = 
  new ObjPool<Long, String>(10, 2);
// 通过对象池获取t,之后执行  
pool.exec(t -> {
    System.out.println(t);
    return t.toString();
});
posted @ 2021-07-06 14:03  SpecialSpeculator  阅读(79)  评论(0编辑  收藏  举报