写点什么

Semaphore

用户头像
Geek_571bdf
关注
发布于: 2021 年 05 月 09 日

1. 信号量模型包括:一个计数器、一个等待队列、三个方法:init()、 down()、 up()

init()用于设置计数器的初始值;执行 down()操作,计数器减 1,如果此时计数器小于 0,则当前线程被阻塞;执行 up()操作,计数器加 1,如果此时计数器值小于或等于 0,则唤醒并移除等待队列中的一个线程。

在 Java 中,信号量模型由 Semaphore 类实现,其中 init()、down() 、up() 分别对应构造器、acquire() 和 release()。Semaphore 能保证这三个方法都是原子操作。

 

2. 使用 Semaphore,可以轻松实现一个限流器。所谓限流,指最多允许 N 个线程同时进入临界区。

在使用各种池化资源时,比如连接池、对象池、线程池等等,在同一时刻,一定是允许多个线程同时使用连接池的,并且,在每个连接释放前,不允许其它线程使用。


class ObjPool<T, R> { // 对象池,一次创建N个对象,然后多个线程重复利用这N个对象  final List<T> pool;   final Semaphore sem;  ObjPool(int size, T t){    pool = new Vector<T>(){}; // 注意,此处不能换成ArrayList,因为信号量允许多个线程同时进入临界区    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();});
复制代码


3. 信号量与管程对比:

①信号量允许多个线程同时进入临界区;

②信号量一次只能唤醒一个线程;

③信号量没有 Condition 的概念,当线程被唤醒后,会直接运行,而不会去检查此时的临界条件是否已经不满足了,基于此考虑,信号量模型才会设计出只能让一个线程被唤醒,否则就会出现因为缺少 Condition 检查而带来的线程安全问题。


用户头像

Geek_571bdf

关注

还未添加个人签名 2019.06.13 加入

还未添加个人简介

评论

发布
暂无评论
Semaphore