【JUC源码解析】Semaphore
简介
Semaphore(信号量),概念上讲,一个信号量持有一组许可(permits)。
概述
线程可调用它的acquire()方法获取一个许可,不成功则阻塞;调用release()方法来归还一个许可,前提是已经拿到过一个许可。然而,并没有什么实际的许可对象,Semaphore只是记录了一个数字,并根据这个数字管控线程。
应用
描述
有一组数据items,其实是26个大写的英文字母,有52个线程从中取数据(getItem),每个线程取一个数据,有一个线程不停地往里面放数据(putItem)直至取数据的52个线程都取到了数据。有一个信号量(Semaphore),要求同时只能有10个线程从中取数据(取数据之前会拿一个许可,共有10许可),除非,某个线程取得的数据,又被放数据的线程放进去了,模拟取数据线程操作结束,把许可证归还,其他取数据线程才能从中拿到许可,然后取数据。
代码
1 public class Pool { 2 private static final int MAX_AVAILABLE = 10; 3 private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); 4 5 public String getItem() throws InterruptedException { 6 available.acquire(); 7 return getNextAvailableItem(); 8 } 9 10 public void putItem(String x) { 11 if (markAsUnused(x)) 12 available.release(); 13 } 14 15 private static void sleep(int sleep) { 16 try { 17 Thread.sleep(sleep); 18 } catch (InterruptedException e) { 19 Thread.currentThread().interrupt(); 20 } 21 } 22 23 protected boolean[] used = new boolean[MAX_AVAILABLE]; 24 25 protected synchronized String getNextAvailableItem() { 26 for (int i = 0; i < MAX_AVAILABLE; ++i) { 27 if (!used[i]) { 28 used[i] = true; 29 return items[i]; 30 } 31 } 32 return null; 33 } 34 35 int len = 26; 36 protected String[] items = new String[len]; 37 { 38 initial(0); 39 } 40 41 void initial(int sleep) { 42 for (int i = 0; i < len; i++) { 43 sleep(sleep); 44 items[i] = String.valueOf((char) (i + 65)); 45 putItem(items[i]); 46 } 47 } 48 49 protected synchronized boolean markAsUnused(String item) { 50 for (int i = 0; i < MAX_AVAILABLE; ++i) { 51 if (item == items[i]) { 52 if (used[i]) { 53 used[i] = false; 54 return true; 55 } else 56 return false; 57 } 58 } 59 return false; 60 } 61 62 public static void main(String[] args) { 63 final Pool pool = new Pool(); 64 65 final AtomicBoolean hasDone = new AtomicBoolean(false); 66 67 ExecutorService es = Executors.newFixedThreadPool(52); 68 69 new Thread(new Runnable() { // 计时器,每10毫秒记录一次 70 @Override 71 public void run() { 72 while (!hasDone.get()) { 73 System.out.print("."); 74 sleep(10); 75 } 76 77 } 78 }).start(); 79 new Thread(new Runnable() { // 1秒后,每20毫秒添加一个元素 80 @Override 81 public void run() { 82 sleep(1000); 83 while (!hasDone.get()) { 84 pool.initial(20); 85 } 86 } 87 }).start(); 88 89 final CyclicBarrier barrier = new CyclicBarrier(52, new Runnable() { 90 @Override 91 public void run() { 92 hasDone.set(true); 93 } 94 }); 95 for (int i = 0; i < 52; i++) { 96 es.execute(new Runnable() { 97 @Override 98 public void run() { 99 try { 100 System.out.println(Thread.currentThread() + " << " + pool.getItem()); 101 barrier.await(); 102 } catch (InterruptedException e) { 103 Thread.currentThread().interrupt(); 104 } catch (BrokenBarrierException e) { 105 e.printStackTrace(); 106 } 107 } 108 }); 109 } 110 es.shutdown(); 111 } 112 }
输出
.Thread[pool-1-thread-1,5,main] << A Thread[pool-1-thread-2,5,main] << B Thread[pool-1-thread-3,5,main] << C Thread[pool-1-thread-4,5,main] << D Thread[pool-1-thread-5,5,main] << E Thread[pool-1-thread-6,5,main] << F Thread[pool-1-thread-7,5,main] << G Thread[pool-1-thread-8,5,main] << H Thread[pool-1-thread-10,5,main] << I Thread[pool-1-thread-9,5,main] << J ...............................................................................................Thread[pool-1-thread-12,5,main] << A ..Thread[pool-1-thread-11,5,main] << B ..Thread[pool-1-thread-13,5,main] << C ..Thread[pool-1-thread-14,5,main] << D ..Thread[pool-1-thread-15,5,main] << E ..Thread[pool-1-thread-16,5,main] << F ..Thread[pool-1-thread-17,5,main] << G ..Thread[pool-1-thread-18,5,main] << H ..Thread[pool-1-thread-19,5,main] << I .Thread[pool-1-thread-20,5,main] << J ...............................Thread[pool-1-thread-21,5,main] << A ..Thread[pool-1-thread-22,5,main] << B ..Thread[pool-1-thread-24,5,main] << C ..Thread[pool-1-thread-23,5,main] << D ..Thread[pool-1-thread-25,5,main] << E ..Thread[pool-1-thread-26,5,main] << F ..Thread[pool-1-thread-27,5,main] << G ..Thread[pool-1-thread-28,5,main] << H ..Thread[pool-1-thread-29,5,main] << I ..Thread[pool-1-thread-30,5,main] << J .................................Thread[pool-1-thread-31,5,main] << A ...Thread[pool-1-thread-32,5,main] << B .Thread[pool-1-thread-33,5,main] << C ..Thread[pool-1-thread-34,5,main] << D ..Thread[pool-1-thread-35,5,main] << E ..Thread[pool-1-thread-36,5,main] << F ..Thread[pool-1-thread-37,5,main] << G ..Thread[pool-1-thread-38,5,main] << H ..Thread[pool-1-thread-39,5,main] << I ..Thread[pool-1-thread-42,5,main] << J .................................Thread[pool-1-thread-41,5,main] << A ..Thread[pool-1-thread-40,5,main] << B ..Thread[pool-1-thread-43,5,main] << C ..Thread[pool-1-thread-44,5,main] << D ..Thread[pool-1-thread-52,5,main] << E ..Thread[pool-1-thread-45,5,main] << F ..Thread[pool-1-thread-51,5,main] << G ..Thread[pool-1-thread-50,5,main] << H ..Thread[pool-1-thread-49,5,main] << I ..Thread[pool-1-thread-48,5,main] << J .................................Thread[pool-1-thread-47,5,main] << A ..Thread[pool-1-thread-46,5,main] << B
从上面输出可知,每10条记录,都要等一段时间,恰好体现了信号量管控的现象
源码分析
同步器对象
1 private final Sync sync; // 同步器对象
内部类
Sync
1 abstract static class Sync extends AbstractQueuedSynchronizer { // 内部类,继承自AQS 2 private static final long serialVersionUID = 1192457210091910933L; 3 4 Sync(int permits) { // 构造方法 5 setState(permits); // 初始化许可的个数,对应state 6 } 7 8 final int getPermits() { // 获取当前许可的个数 9 return getState(); 10 } 11 12 final int nonfairTryAcquireShared(int acquires) { // 获取锁,默认非公平锁 13 for (;;) { 14 int available = getState(); // 获取当前state,可用permits个数 15 int remaining = available - acquires; // 可用 - 获取 = 剩余 16 if (remaining < 0 || compareAndSetState(available, remaining)) // 如果remaining小于0,直接返回;否则CAS 17 // state为remaining,成功则返回,失败,则重新获取 18 return remaining; 19 } 20 } 21 22 protected final boolean tryReleaseShared(int releases) { // 释放锁 23 for (;;) { 24 int current = getState(); // 获取当前状态 25 int next = current + releases; // 当前值 + 释放值 = 下次可用值 26 if (next < current) // 溢出,说明releases的值小于0 27 throw new Error("Maximum permit count exceeded"); 28 if (compareAndSetState(current, next)) // CAS state 29 // 为next,成功则返回;否则,重新获取并释放 30 return true; 31 } 32 } 33 34 final void reducePermits(int reductions) { // 减少许可个数 35 for (;;) { 36 int current = getState(); // 当前可用的个数 37 int next = current - reductions; // 剩余 38 if (next > current) // 说明reductions小于0 39 throw new Error("Permit count underflow"); 40 if (compareAndSetState(current, next)) // CAS state为next,成功则返回;否则,重新获取并减少 42 return; 43 } 44 } 45 46 final int drainPermits() { // 排空许可,即情况所有的许可 47 for (;;) { 48 int current = getState(); // 获取当前状态 49 if (current == 0 || compareAndSetState(current, 0)) // CAS state 50 // 为0 51 return current; 52 } 53 } 54 }
NonfairSync
1 static final class NonfairSync extends Sync { // 非公平 2 private static final long serialVersionUID = -2694183684443567898L; 3 4 NonfairSync(int permits) { 5 super(permits); // 调用父类构造方法 6 } 7 8 protected int tryAcquireShared(int acquires) { 9 return nonfairTryAcquireShared(acquires); // 直接调用父类方法 10 } 11 }
FairSync
1 static final class FairSync extends Sync { // 公平 2 private static final long serialVersionUID = 2014338818796000944L; 3 4 FairSync(int permits) { 5 super(permits); // 调用父类构造方法 6 } 7 8 protected int tryAcquireShared(int acquires) { 9 for (;;) { 10 if (hasQueuedPredecessors()) // 如果等待队列里有元素,直接返回失败,目的是让线程入队等待,保证公平性 11 return -1; 12 int available = getState(); // 后面同非公平逻辑 13 int remaining = available - acquires; 14 if (remaining < 0 || compareAndSetState(available, remaining)) 15 return remaining; 16 } 17 } 18 }
构造方法
1 public Semaphore(int permits) { 2 sync = new NonfairSync(permits); // 默认非公平 3 } 4 5 public Semaphore(int permits, boolean fair) { // 根据fair参数选择公平或非公平 6 sync = fair ? new FairSync(permits) : new NonfairSync(permits); 7 }
其它方法
1 public void acquire() throws InterruptedException { 2 sync.acquireSharedInterruptibly(1); // 获取许可,响应中断 3 } 4 5 public void acquireUninterruptibly() { 6 sync.acquireShared(1); // 不响应中断 7 } 8 9 public boolean tryAcquire() { 10 return sync.nonfairTryAcquireShared(1) >= 0; // false: < 0 true: > 0 11 } 12 13 public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { 14 return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); // 支持超时 15 } 16 17 public void release() { 18 sync.releaseShared(1); // 释放许可 19 } 20 21 public void acquire(int permits) throws InterruptedException { // 获取多个 22 if (permits < 0) 23 throw new IllegalArgumentException(); 24 sync.acquireSharedInterruptibly(permits); // 响应中断 25 } 26 27 public void acquireUninterruptibly(int permits) { // 不响应中断 28 if (permits < 0) 29 throw new IllegalArgumentException(); 30 sync.acquireShared(permits); 31 } 32 33 public boolean tryAcquire(int permits) { // false: < 0 true: > 0 34 if (permits < 0) 35 throw new IllegalArgumentException(); 36 return sync.nonfairTryAcquireShared(permits) >= 0; 37 } 38 39 public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { 40 if (permits < 0) 41 throw new IllegalArgumentException(); 42 return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout)); // 支持超时 43 } 44 45 public void release(int permits) { // 释放多个 46 if (permits < 0) 47 throw new IllegalArgumentException(); 48 sync.releaseShared(permits); 49 } 50 51 public int availablePermits() { // 可用的许可个数 52 return sync.getPermits(); 53 } 54 55 public int drainPermits() { // 排空 56 return sync.drainPermits(); 57 } 58 59 protected void reducePermits(int reduction) { // 减少 60 if (reduction < 0) 61 throw new IllegalArgumentException(); 62 sync.reducePermits(reduction); 63 } 64 65 public boolean isFair() { // 是否是公平的 66 return sync instanceof FairSync; 67 } 68 69 public final boolean hasQueuedThreads() { 70 return sync.hasQueuedThreads(); // 队列里是否还有等待的线程 71 } 72 73 public final int getQueueLength() { 74 return sync.getQueueLength(); // 队列长度,等待线程的个数 75 } 76 77 protected Collection<Thread> getQueuedThreads() { 78 return sync.getQueuedThreads(); // 获取在对列里等待的线程 79 } 80 81 public String toString() { // toString()方法 82 return super.toString() + "[Permits = " + sync.getPermits() + "]"; 83 }
源码比较简单。
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_semaphore.html