CountDownLatch
允许一个或多个线程等待其他线程完成操作。只能使用一次
join方式原理是while循环不断的去检查join线程是否存活,存活则让当前线程等待,直到join线程中止,线程的this.notifyAll会被调用,而调用是在JVM里实现的。
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
CountDownLatch可也实现join的效果,且更加的高效。
一个线程调用countDown方法happen-before,另外一个线程调用await方法
实现原理继承了AQS ,每次state减1,直到等于0是释放锁。
每次countDown减1 protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.SHARED); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head) { int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
同步屏障 CyclicBarrier
让一个线程到达一个屏障时被阻塞,直到最后一个线程到达屏障。屏障才会开门,所有被屏障拦截的线程才会继续运行。可重置屏障反复执行。
public CyclicBarrier(int parties, Runnable barrierAction) 屏障数量到达时,优先执行barrierAction。
利用ReentrantLock 和condition实现
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation; if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } //每次await -1 直到等于0 breakBarrier()唤醒所有线程 int index = --count; if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out //count 等于0 则进入死循环 for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.currentThread().interrupt(); } } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } }
应用场景,多线程计算 最终合并结果。
控制并发线程数Semaphore(信号量)
控制同时访问特定资源的线程数量,通过协调各个线程,保证合理的使用公共资源。应用:流量控制
非公平不进入同步队列//判断设置的许可证是否小于0,大于0 还有可用的许可证。小于0没有进入阻塞。 public void acquire() throws InterruptedException { sync.acquireSharedInterruptibly(1); } public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); } final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.SHARED); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head) { int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } //释放时,许可证数量加一 public void release() { sync.releaseShared(1); } public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false; } protected final boolean tryReleaseShared(int releases) { for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetState(current, next)) return true; } }
ExChanger线程间交换数据
Exchanger (交 换 者)是一个用于 线 程 间协 作的工具 类 。 Exchanger 用于 进 行 线 程 间 的数据交 换。它提供一个同步点,在 这个同步点,两个线程可以交换 彼此的数据。 这两个线程通过 exchange方法交换 数据,如果第一个 线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换 数据,将本 线 程生 产 出来的数据传递给对 方,一个线程执行exchange,另一个未执行,会进入阻塞。多线程间的数据校对、遗传算法。private final Object slotExchange(Object item, boolean timed, long ns) { Node p = participant.get(); Thread t = Thread.currentThread(); if (t.isInterrupted()) // preserve interrupt status so caller can recheck return null; for (Node q;;) { if ((q = slot) != null) { if (U.compareAndSwapObject(this, SLOT, q, null)) { Object v = q.item; q.match = item; Thread w = q.parked; if (w != null) U.unpark(w); return v; } // create arena on contention, but continue until slot null if (NCPU > 1 && bound == 0 && U.compareAndSwapInt(this, BOUND, 0, SEQ)) arena = new Node[(FULL + 2) << ASHIFT]; } else if (arena != null) return null; // caller must reroute to arenaExchange else { p.item = item; if (U.compareAndSwapObject(this, SLOT, null, p)) break; p.item = null; } } // await release int h = p.hash; long end = timed ? System.nanoTime() + ns : 0L; int spins = (NCPU > 1) ? SPINS : 1; Object v; while ((v = p.match) == null) { if (spins > 0) { h ^= h << 1; h ^= h >>> 3; h ^= h << 10; if (h == 0) h = SPINS | (int)t.getId(); else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0) Thread.yield(); } else if (slot != p) spins = SPINS; else if (!t.isInterrupted() && arena == null && (!timed || (ns = end - System.nanoTime()) > 0L)) { U.putObject(t, BLOCKER, this); p.parked = t; if (slot == p) U.park(false, ns); p.parked = null; U.putObject(t, BLOCKER, null); } else if (U.compareAndSwapObject(this, SLOT, p, null)) { v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null; break; } } U.putOrderedObject(p, MATCH, null); p.item = null; p.hash = h; return v; }