Semaphore、CountDownLatch、CyclicBarrier、Exchanger、Phaser源码

Semaphore

Semaphore最主要功能特点,是控制同时访问特定资源的线程数量。

其源码实现就是在初始化时传入permits参数,紧接着调用AQS同步器setState方法,将内存中state值设为permits传入的参数值;

而当要同时访问的线程数, 大于state的值,即remaining小于0时,线程加入同步器中队列进行等待。

public class Semaphore implements java.io.Serializable {
    abstract static class Sync extends AbstractQueuedSynchronizer {
        Sync(int permits) {
            setState(permits);
        }
    }
    
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
    
    static final class NonfairSync extends Sync {
        NonfairSync(int permits) {
            super(permits);
        }
    }
}

remaining = available - acquires
当acquire传入的permits值小于等于state值,更新state值为当前remaining的值
当acquire传入的值大于state的值,即remaining小于0,走doAcquireSharedInterruptibly逻辑,加入等待队列。

public class Semaphore implements java.io.Serializable {
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }
    
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    
    //非公平锁
    static final class NonfairSync extends Sync {
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }
    
    abstract static class Sync extends AbstractQueuedSynchronizer {
       final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }
}
CountDownLatch

CountDownLatch功能特点是一个或多个线程等待其他线程完成操作。

而源码实现是,每当一个线程完成操作,state值减1;最后当所有线程全部完成操作,state==0,tryAcquire返回1,跳出同步器中doAcquireSharedInterruptibly方法中的死循环,进行下一步。

CountDownLatch的初始设置state值的逻辑同上Semaphore

public class CountDownLatch {
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    
    private static final class Sync extends AbstractQueuedSynchronizer {
        Sync(int count) {
            初始化state值
            setState(count);
        }
    }
}

await方法每次同步器进行state减1

public class CountDownLatch {
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    private static final class Sync extends AbstractQueuedSynchronizer {
        protected int tryAcquireShared(int acquires) {
            // state==0时,跳出死循环
            return (getState() == 0) ? 1 : -1;
        }
    }
}
public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            //只要有一个未到达,就执行里面循环获取锁
            doAcquireSharedInterruptibly(arg);
    }
    
    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

CyclicBarrier等待所有线程都到达屏障,屏障才开门,所有被屏障拦截的线程才会继续运行。功能类似于CountDownLatch,但可以重置计数器、增加barrierAction方法等功能,可以比CountDownLatch实现更复杂的业务。

源码实现是通过在dowait方法中用ReentrantLock加锁解锁实现,每次调用await方法,进行加锁,同时count值进行减1,当所有线程都到达屏障,如果有barrierAction方法,执行barrierAction方法

而当超时等条件都满足后进行unlock,否则进行等待陷入死循环中。

    public CyclicBarrier(int parties) {
        this(parties, null);
    }

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    
    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();
            }
            // 线程计数
            int index = --count;
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    //所有线程都到达屏障,如果有action,执行action
                    if (command != null)
                        command.run();
                    ranAction = true;
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            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();
        }
    }
Exchanger

Exchanger用于进行线程间的数据交换,它提供一个同步点(第一个线程等待第二个线程也执行exchange方法),两个线程可以交换彼此的数据。

Exchanger里面写了个内部类Participant,Participant继承ThreadLocal,每个线程数据保存在ThreadLocal中。

更详细源码解释可参考:https://blog.csdn.net/wzl1369248650/article/details/104263283

    public Exchanger() {
        participant = new Participant();
    }
    
    static final class Participant extends ThreadLocal<Node> {
        public Node initialValue() { return new Node(); }
    }
    
    @sun.misc.Contended static final class Node {
        int index;              // Arena index
        int bound;              // Last recorded value of Exchanger.bound
        int collides;           // Number of CAS failures at current bound
        int hash;               // Pseudo-random for spins
        Object item;            // This thread's current item
        volatile Object match;  // Item provided by releasing thread
        volatile Thread parked; // Set to this thread when parked, else null
    }
    
    public V exchange(V x, long timeout, TimeUnit unit)
        throws InterruptedException, TimeoutException {
        Object v;
        Object item = (x == null) ? NULL_ITEM : x;
        long ns = unit.toNanos(timeout);
        if ((arena != null ||
            // 数据交换入口
             (v = slotExchange(item, true, ns)) == null) &&
            ((Thread.interrupted() ||
              (v = arenaExchange(item, true, ns)) == null)))
            throw new InterruptedException();
        if (v == TIMED_OUT)
            throw new TimeoutException();
        return (v == NULL_ITEM) ? null : (V)v;
    }
Phaser

参考:https://www.cnblogs.com/tong-yuan/p/11614755.html

Phaser相对于CyclicBarrier和CountDownLatch的优势:

  1. Phaser可以完成多阶段,而一个CyclicBarrier或者CountDownLatch一般只能控制一到两个阶段的任务;

  2. Phaser可动态注册屏障数,每个阶段的任务数量可以控制,而一个CyclicBarrier或者CountDownLatch任务数量一旦确定不可修改。

posted @ 2020-12-18 15:16  曹自标  阅读(100)  评论(0编辑  收藏  举报