1. Semaphore----[ˈseməfɔːr]
信号量可以理解为限流算法令牌算法里的令牌池,他是对锁的扩展,无论synchronized还是Lock一次只允许一个线程访问资源,而Semaphore内部维护了一个信号量计数器,当线程访问资源时将计数器减一,访问完毕后计数器加一,当计数器减到0时再有线程来获取锁将会等待,当有一个线程执行完毕释放锁后计数器加一不为0,此时等待的线程可以获取锁并把计数器减一。
其构造函数:
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
permits:信号计数器初始值
fair:是否公平锁
其常用方法:
acquire()
tryAcquire()
tryAcquire(long timeout, TimeUnit unit)
acquireUninterruptibly():不响应中断
release()
用法与Lock的相关用法是一样的,这里不细述了,可以看多线程基础(四)Lock
2. 示例
控制最多同时只能有两个线程拿到锁
public class Test05 {
// [ˈseməfɔːr] 信号量
private static Semaphore semaphore = new Semaphore(2);
private static int coreSize = 10;
private static long timeOut = 10;
private static LinkedBlockingQueue queue = new LinkedBlockingQueue<>();
private static TimeUnit timeUnit = TimeUnit.SECONDS;
private static AtomicInteger index = new AtomicInteger(0);
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, coreSize, timeOut, timeUnit, queue);
long start = System.currentTimeMillis();
for (int i = 0; i < 8; i++) {
executor.submit(() -> {
try {
semaphore.acquire();
TimeUnit.SECONDS.sleep(1);
int name = index.incrementAndGet();
System.out.println("第" + name + "个线程执行完毕:" + (System.currentTimeMillis() - start) / 1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
});
}
executor.shutdown();
}
}
执行结果:
第1个线程执行完毕:1
第2个线程执行完毕:1
第3个线程执行完毕:2
第4个线程执行完毕:2
第5个线程执行完毕:3
第6个线程执行完毕:3
第7个线程执行完毕:4
第8个线程执行完毕:4