Semaphore也叫信号量,在JDK1.5被引入,用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。还可以用来实现某种资源池,或者对容器施加边界。
Semaphore内部维护了一组虚拟的许可,许可的数量可以通过构造函数的参数指定。
访问特定资源前,必须使用acquire方法获得许可,如果许可数量为0,该线程则一直阻塞,直到有可用许可。
访问资源后,使用release释放许可。
Semaphore和ReentrantLock类似,获取许可有公平策略和非公平许可策略,默认情况下使用非公平策略。
当初始值为1时,可以用作互斥锁,并具备不可重入的加锁语义。
Semaphore将AQS的同步状态用于保存当前可用许可的数量。
实现资源池:
一个固定长度的资源池,当池为空时,请求资源会失败。
使用Semaphore可以实现当池为空时,请求会阻塞,非空时解除阻塞。
也可以使用Semaphore将任何一种容器变成有界阻塞容器。
1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.Semaphore; 4 5 6 public class SemaPhore { 7 public static void main(String[] args) { 8 // 线程池 9 ExecutorService exec = Executors.newCachedThreadPool(); 10 // 只能5个线程同时访问 11 final Semaphore semp = new Semaphore(5); 12 // 模拟20个客户端访问 13 for (int index = 0; index < 20; index++) { 14 final int NO = index; 15 Runnable run = new Runnable() { 16 public void run() { 17 try { 18 // 获取许可 19 semp.acquire(); 20 System.out.println("Accessing: " + NO); 21 Thread.sleep((long) (Math.random() * 6000)); 22 // 访问完后,释放 23 semp.release(); 24 //availablePermits()指还剩多少个许可 25 System.out.println("-----------------" + semp.availablePermits()); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 }; 31 exec.execute(run); 32 } 33 // 退出线程池 34 exec.shutdown(); 35 } 36 }