我们调用Semaphore方法时,其实是在间接调用其内部类或AQS方法执行的。Semaphore类结构与ReetrantLock类相似,内部类Sync继承自AQS,然后其子类FairSync和NoFairSync分别实现公平锁和非公平锁的获取锁方法tryAcquireShared(int arg),而释放锁的tryReleaseShared(int arg)方法则有Sync类实现,因为非公平或公平锁的释放过程都是相同的。
AQS通过state值来控制对共享资源访问的线程数,有线程请求同步状态成功state值减1,若超过共享资源数量获取同步状态失败,则将线程封装共享模式的Node结点加入到同步队列等待。有线程执行完任务释放同步状态后,state值会增加1,同步队列中的线程才有机会获得执行权。公平锁与非公平锁不同在于公平锁申请获取同步状态前都会先判断同步队列中释放存在Node,若有则将当前线程封装成Node结点入队,从而保证按FIFO的方式获取同步状态,而非公平锁则可以直接通过竞争获取线程执行权。
1//Semaphore的acquire() 2public void acquire() throws InterruptedException { 3 sync.acquireSharedInterruptibly(1); 4 } 5 6/** 7* 注意Sync类继承自AQS 8* AQS的acquireSharedInterruptibly()方法 9*/ 10public final void acquireSharedInterruptibly(int arg) 11 throws InterruptedException { 12 //判断是否中断请求 13 if (Thread.interrupted()) 14 throw new InterruptedException(); 15 //如果tryAcquireShared(arg)不小于0,则线程获取同步状态成功 16 if (tryAcquireShared(arg) < 0) 17 //未获取成功加入同步队列等待 18 doAcquireSharedInterruptibly(arg); 19} 20//Semaphore中非公平锁NonfairSync的tryAcquireShared() 21protected int tryAcquireShared(int acquires) { 22 //调用了父类Sync中的实现方法 23 return nonfairTryAcquireShared(acquires); 24} 25 26final int nonfairTryAcquireShared(int acquires) { 27 //使用死循环 28 for (;;) { 29 int available = getState(); 30 int remaining = available - acquires; 31 //判断信号量是否已小于0或者CAS执行是否成功 32 if (remaining < 0 || 33 compareAndSetState(available, remaining)) 34 return remaining; 35 } 36 } 37private void doAcquireSharedInterruptibly(int arg) 38 throws InterruptedException { 39 //创建共享模式的结点Node.SHARED,并加入同步队列 40 final Node node = addWaiter(Node.SHARED); 41 boolean failed = true; 42 try { 43 //进入自旋操作 44 for (;;) { 45 final Node p = node.predecessor(); 46 //判断前驱结点是否为head 47 if (p == head) { 48 //尝试获取同步状态 49 int r = tryAcquireShared(arg); 50 //如果r>0 说明获取同步状态成功 51 if (r >= 0) { 52 //将当前线程结点设置为头结点并传播 53 setHeadAndPropagate(node, r); 54 p.next = null; // help GC 55 failed = false; 56 return; 57 } 58 } 59 //调整同步队列中node结点的状态并判断是否应该被挂起 60 //并判断是否需要被中断,如果中断直接抛出异常,当前结点请求也就结束 61 if (shouldParkAfterFailedAcquire(p, node) && 62 parkAndCheckInterrupt()) 63 throw new InterruptedException(); 64 } 65 } finally { 66 if (failed) 67 //结束该结点线程的请求 68 cancelAcquire(node); 69 } 70 } 71 72private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { 73 //获取当前结点的等待状态 74 int ws = pred.waitStatus; 75 //如果为等待唤醒(SIGNAL)状态则返回true 76 if (ws == Node.SIGNAL) 77 return true; 78 //如果ws>0 则说明是结束状态, 79 //遍历前驱结点直到找到没有结束状态的结点 80 if (ws > 0) { 81 do { 82 node.prev = pred = pred.prev; 83 } while (pred.waitStatus > 0); 84 pred.next = node; 85 } else { 86 //如果ws小于0又不是SIGNAL状态, 87 //则将其设置为SIGNAL状态,代表该结点的线程正在等待唤醒。 88 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); 89 } 90 return false; 91 } 92 93private final boolean parkAndCheckInterrupt() { 94 //将当前线程挂起 95 LockSupport.park(this); 96 //获取线程中断状态,interrupted()是判断当前中断状态, 97 //并非中断线程,因此可能true也可能false,并返回 98 return Thread.interrupted(); 99} 100 101//不可中的acquireShared() 102public final void acquireShared(int arg) { 103 if (tryAcquireShared(arg) < 0) 104 doAcquireShared(arg); 105} 106 107private void doAcquireShared(int arg) { 108 final Node node = addWaiter(Node.SHARED); 109 boolean failed = true; 110 try { 111 boolean interrupted = false; 112 for (;;) { 113 final Node p = node.predecessor(); 114 if (p == head) { 115 int r = tryAcquireShared(arg); 116 if (r >= 0) { 117 setHeadAndPropagate(node, r); 118 p.next = null; // help GC 119 if (interrupted) 120 selfInterrupt(); 121 failed = false; 122 return; 123 } 124 } 125 if (shouldParkAfterFailedAcquire(p, node) && 126 parkAndCheckInterrupt()) 127 //没有抛出异常中的。。。。 128 interrupted = true; 129 } 130 } finally { 131 if (failed) 132 cancelAcquire(node); 133 } 134 } 135 136 private void setHeadAndPropagate(Node node, int propagate) { 137 Node h = head; // Record old head for check below 138 setHead(node);//设置为头结点 139 /* 140 * 尝试去唤醒队列中的下一个节点,如果满足如下条件: 141 * 调用者明确表示"传递"(propagate > 0), 142 * 或者h.waitStatus为PROPAGATE(被上一个操作设置) 143 * 并且 144 * 下一个节点处于共享模式或者为null。 145 * 146 * 这两项检查中的保守主义可能会导致不必要的唤醒,但只有在有 147 * 有在多个线程争取获得/释放同步状态时才会发生,所以大多 148 * 数情况下会立马获得需要的信号 149 */ 150 if (propagate > 0 || h == null || h.waitStatus < 0 || 151 (h = head) == null || h.waitStatus < 0) { 152 Node s = node.next; 153 if (s == null || s.isShared()) 154 //唤醒后继节点,因为是共享模式,所以允许多个线程同时获取同步状态 155 doReleaseShared(); 156 } 157 } 158 159//Semaphore的release() 160public void release() { 161 sync.releaseShared(1); 162} 163 164//调用到AQS中的releaseShared(int arg) 165public final boolean releaseShared(int arg) { 166 //调用子类Semaphore实现的tryReleaseShared方法尝试释放同步状态 167 if (tryReleaseShared(arg)) { 168 doReleaseShared(); 169 return true; 170 } 171 return false; 172 } 173 174//在Semaphore的内部类Sync中实现的 175protected final boolean tryReleaseShared(int releases) { 176 for (;;) { 177 //获取当前state 178 int current = getState(); 179 //释放状态state增加releases 180 int next = current + releases; 181 if (next < current) // overflow 182 throw new Error("Maximum permit count exceeded"); 183 //通过CAS更新state的值 184 if (compareAndSetState(current, next)) 185 return true; 186 } 187 } 188 189private void doReleaseShared() { 190 /* 191 * 保证释放动作(向同步等待队列尾部)传递,即使没有其他正在进行的 192 * 请求或释放动作。如果头节点的后继节点需要唤醒,那么执行唤醒 193 * 动作;如果不需要,将头结点的等待状态设置为PROPAGATE保证 194 * 唤醒传递。另外,为了防止过程中有新节点进入(队列),这里必 195 * 需做循环,所以,和其他unparkSuccessor方法使用方式不一样 196 * 的是,如果(头结点)等待状态设置失败,重新检测。 197 */ 198 for (;;) { 199 Node h = head; 200 if (h != null && h != tail) { 201 // 获取头节点对应的线程的状态 202 int ws = h.waitStatus; 203 // 如果头节点对应的线程是SIGNAL状态,则意味着头 204 //结点的后继结点所对应的线程需要被unpark唤醒。 205 if (ws == Node.SIGNAL) { 206 // 修改头结点对应的线程状态设置为0。失败的话,则继续循环。 207 if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 208 continue; 209 // 唤醒头结点h的后继结点所对应的线程 210 unparkSuccessor(h); 211 } 212 else if (ws == 0 && 213 !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) 214 continue; // loop on failed CAS 215 } 216 // 如果头结点发生变化,则继续循环。否则,退出循环。 217 if (h == head) // loop if head changed 218 break; 219 } 220} 221 222 223//唤醒传入结点的后继结点对应的线程 224private void unparkSuccessor(Node node) { 225 int ws = node.waitStatus; 226 if (ws < 0) 227 compareAndSetWaitStatus(node, ws, 0); 228 //拿到后继结点 229 Node s = node.next; 230 if (s == null || s.waitStatus > 0) { 231 s = null; 232 for (Node t = tail; t != null && t != node; t = t.prev) 233 if (t.waitStatus <= 0) 234 s = t; 235 } 236 if (s != null) 237 //唤醒该线程 238 LockSupport.unpark(s.thread); 239 }