countDownLatch(CAS+UNSAFE.park)和cyclicBarrier(ReentrantLock+count自减+condiiton.await)

countDownLatch(CAS+UNSAFE.park)和cyclicBarrier(ReentrantLock)

countDownLatch 

 AQS(CAS-state)
初始化时,state被初始化
调用await,判断state的值,如果state=0,则不会阻塞线程;否则在哪个线程执行执行就会阻塞(UNSAFE.park)哪个线程。
然后countDown被调用,每调用一次,state会被减一,并判断此时state是否等于0,如果等于0则释放((UNSAFE.unpark))被阻塞线程

new countDownLatch的相关代码:新建AQS的子类Sync,初始化state的值
 

   public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }
        // state=0才获取到锁
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
        // 减1后如果值为0表示获取了共享锁,释放锁
        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;
            }
        }
    }


    await方法调用逻辑:

    public void await() 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);
    }

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    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);
        }
    }

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
    // 最终调用unsafe类阻塞线程
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }


    countdown方法调用:

    public void countDown() {
        sync.releaseShared(1);
    }  

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

    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 doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

    //unparkSuccessor方法中最终释放锁:
    LockSupport.unpark(s.thread);


cyclicBarrier 

await为啥可以暂停自身(condition.await),await达到一定次数怎么放行的(condiition.signalAll)? 
底层实现:ReentantLock + condition,每次调用await,先lock,后count--,判断count==0?singnal:con.await

CyclicBarrier的两个属性:
/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();


构造器:

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

await方法的调用:
   

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,await次数已够,放行
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    // 这里面调用condition.signal 唤醒所有的线程
                    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();
        }
    }
    // 这里唤醒阻塞的线程
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        count = parties;
        generation = new Generation();
    }


cyclic怎么理解,其中generation起到什么作用?

CyclicBarrier可以重复使用,条件是await达到次数或者调用reset方法均可,调用reset已经那些已经调用await的线程是怎么处理的?
会直接报BrokenBarrierException异常,程序不再执行。

reset时BrokenBarrierException异常怎么抛出来的?
public void reset() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        breakBarrier();   // break the current generation
        nextGeneration(); // start a new generation
    } finally {
        lock.unlock();
    }
}
很明显reset没有直接抛出异常,但是 breakBarrier了,即
    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }

再仔细看下会发现doawait方法中,死循环中有这么一段代码:
if (g.broken)
    throw new BrokenBarrierException();
这就对上了。。。。。。
CylicBarrier使用实例
 

  public static void main(String[] args) throws InterruptedException, BrokenBarrierException {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> System.out.println("aa"));

        new Thread(new Innner(cyclicBarrier)).start();
        // 确保reset后于上面的thread1执行
        Thread.sleep(100);
        cyclicBarrier.reset();
        new Thread(new Innner(cyclicBarrier)).start();
        cyclicBarrier.await();
    }

    static  class Innner implements Runnable{
        CyclicBarrier cyclicBarrier;
        public Innner( CyclicBarrier cyclicBarrier){
             this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+" -start");
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName()+" -end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }


countDownLatch和cyclicBarrier使用场景
countDownLatch(3): 商家(主线程)卖西瓜,规矩是必须三人(初始值为3)拼团才发货(调用await),第一个人下单(调用一次countDown),商家看了下没到三人,还差俩人(3-1=2),又有俩人下单,拼团成功,商家发货。

cyclicBarrier(3) :导游(即cyclicBarrier)带领仨人(三个任务线程)逛故宫,需要在故宫门口结合,现在每个人到了报告下(任务线程调用await来),第一个报告的需要等待另外两名游客,三游客都报告了;然后游客可以进门游览故宫,同时导游开始讲解(cyclicBarrier中的任务开始执行)。

countDownLatch和cyclicBarrier实现线程等待 https://blog.csdn.net/h2604396739/article/details/86615541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值