Semaphore是一个计数信号量,它的本质是一个"共享锁"。
信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。
Semaphore经常用于限制获取某种资源的线程数量。例如一个网吧有10台电脑,但是现在来了15个人想上网,此时多出来的5人就只能等待已经在上网的10人当中有人下机了,其他人才能获取上网机会。
示例:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreTest { private static final int SEM_MAX = 10; public static void main(String[] args) { Semaphore sem = new Semaphore(SEM_MAX); //创建线程池 ExecutorService threadPool = Executors.newFixedThreadPool(3); System.out.println("开始执行线程时间:"+System.currentTimeMillis()); //在线程池中执行任务 threadPool.execute(new MyThread2(sem, 5)); threadPool.execute(new MyThread2(sem, 4)); threadPool.execute(new MyThread2(sem, 7)); //关闭池 threadPool.shutdown(); } } class MyThread2 extends Thread { private volatile Semaphore sem; // 信号量 private int count; // 申请信号量的大小 MyThread2(Semaphore sem, int count) { this.sem = sem; this.count = count; } public void run() { try { // 从信号量中获取count个许可 sem.acquire(count); System.out.println(Thread.currentThread().getName() + " acquire count="+count +"。获取可用许可时间:"+System.currentTimeMillis()); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 释放给定数目的许可,将其返回到信号量。 sem.release(count); System.out.println(Thread.currentThread().getName() + " release " + count + "。释放可用许可时间:"+System.currentTimeMillis()); } } }
执行结果:
开始执行线程时间:1525763132285
pool-1-thread-1 acquire count=5。获取可用许可时间:1525763132303
pool-1-thread-2 acquire count=4。获取可用许可时间:1525763132308
pool-1-thread-1 release 5。释放可用许可时间:1525763134307
pool-1-thread-2 release 4。释放可用许可时间:1525763134312
pool-1-thread-3 acquire count=7。获取可用许可时间:1525763134312
pool-1-thread-3 release 7。释放可用许可时间:1525763136312
结果总结:
三个线程如果在信号量够用的情况下的结果应该是几乎同一时间获取到可用许可,然后都在2秒睡眠后释放。
当信号量不够的时候的结果就是如上。线程1和线程2几乎同一时间获取可用许可,但是他们共占用了9个资源,剩下1个可用资源不够线程3分配,导致线程3在sem.acquire(count)时阻塞。等到线程1和线程2都释放完资源后,线程3才立马获取可用许可然后执行。