并发包的同步组件

1,概述

java并发包已经讲解了volatile,synchronized,CAS,AQS机制等。这些都是整个并发的基础,这篇主要讲一下并发包下的一些组件。

2,CountDownLatch

2.1 demo:

首先演示下这个组件的功能。主线程执行到await()方法后,就会同步等待2个线程执行,这里的2就是构造函数传入的。然后再执行下去。

public class CountDownLatchDemo {
    public static void main(String[] args) throws Exception{
        final CountDownLatch latch = new CountDownLatch(2);

        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    System.out.println("线程1执行...");
                    latch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    System.out.println("线程2执行...");
                    latch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }.start();
        System.out.println("主线程即将执行await...");
        latch.await();
        System.out.println("主线程执行...");
    }
}

2.2 构造函数:

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
        //将传入的参数作为state的大小。这里的state即AQS下的state
        Sync(int count) {
            setState(count);
        }

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

这里需要看看tryAcquireShared()方法:

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

很明显,state是我们传入的2,不等于0,会进入方法doAcquireSharedInterruptibly():

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

这个方法前面都分析过,直接画图了:

然后其他线程会执行countDown()方法,源码逻辑很简单,就是依次去减state的值。然后判断state是否等于0,如果state==0,则唤醒队列中main线程。可以发现,熟悉AQS原理之后,这些都是很简单的,所以AQS是并发的基础。

3,CyclicBarrier

3.1 demo:

public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("召唤神龙。。。。。。。。。。。");
            }
        });

        for (int i = 1; i <= 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("收集第" + Thread.currentThread().getName() + "颗");
                    try {
                        cyclicBarrier.await();
                        //等待被唤醒,唤醒后的操作
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, String.valueOf(i)).start();
        }
    }


}

3.2 构造函数:

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


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

构造函数有两种,一种是带Runable,一种是不带的。

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

 通过源码可以知道,await()方法就是充分利用ReentractLock和Condition来实现的。

具体流程说一下:

1,parties=3,线程1进来,将parties减1,变成2.获取锁成功,然后将自己入condition队列,释放锁,挂起

2,这时候可能线程2和线程3已经进入等待队列等着获取锁了。假设这时候线程2获取锁,将parties减1,变成1,然后将自己入condition队列,释放锁,挂起

3,线程3获取锁成功,将parties减1,变i成0.满足条件,会执行传入的Runable对象的run方法。然后将之前的在condition队列的线程执行signalAll(),也就是将其转换到等待队列,然后释放锁。

4,这时候等待队列的线程陆续获取锁,并释放,整个流程跑通。

 

转载于:https://www.cnblogs.com/xtz2018/p/11493982.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值