java学习之多线程辅助类

CyclicBarrier(循环屏障):当多个线程同时执行时,在某个步骤完成时,需要互相等待共同完成,然后在执行时,就可以使用该类.该类的作用就是会实现多个类达到一起行动的作用.

1,构造器:该类有两个构造器,第一个参数是设置有多少条线程数需要等待,然后共同达到某个等待点,第二个参数是传入一个Runnable,当第一个线程到达屏障点的时候,会先执行该接口里的run方法,在后面会在源码里说明.



主要使用方法:await(),里面执行的dowait()

private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;
            //初始值broken是false
            if (g.broken)
                throw new BrokenBarrierException();
                //如果该线程被中断过则抛出异常
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
            //count是计数器,是传入的同步的线程数
            int index = --count;
            //当计数为0时,则先执行Runable接口的方法,然后唤醒所有线程,同时也说明所有线程都到达屏障点了,执行里面唤醒线程的方法
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //该方法会唤醒所有等待的线程,重置generation变量,使得后面还能继续设置屏障
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction) 
                        //该方法会终止屏障,唤醒在屏障出等待的线程
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            //通过自旋锁实现线程在屏障出等待的功能
            for (;;) {
                try {
                    if (!timed)
                        //condition的wait方法使得调用的线程进入等待状态
                        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();
        }
    }

通过对该方法的分析,大体知道该类的实现原理了.

案例:

import java.util.concurrent.CyclicBarrier;
class CyclicBarrierDemo {
    /**
     * CyclicBarrier:关卡
     * 它约束多线程必需同时达到某时刻,同时向下执行,在没有达到之前保持等待
     * 比如:周末约定去爬山,在公司门口集合,必须要等所有人都到后大家在一起出发。
     */
    static void test(int threadNum) {
        //        CyclicBarrier cyclicBarrier  = new CyclicBarrier(3);
        // 构造方法可支持一个Runnable,用于在所有线程都达到后首先执行。
        final CyclicBarrier cyclicBarrier  = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("都准备好了!");
            }
        });
        for (int i = 0; i < threadNum; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("线程" + Thread.currentThread().getName() + " 已经准备好.");
                        cyclicBarrier.await();
                        Thread.sleep((long) (Math.random() * 2000));
                        System.out.println("线程" + Thread.currentThread().getName() + " 处理完毕,汇报结果!");
                    } catch (Exception e) {}
                }
            }).start();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        CyclicBarrierDemo.test(3);
    }
}

CountDownLatch:该类和CyclicBarrier类功能类似,都是设置屏障使多个线程达到在某个点后,互相等待,都到达时在唤醒其他等待线程,共同执行下面的业务逻辑.但是该类能设置一次屏障.举例:比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

1构造器:传入的参数是计数器,显示要等待多少个线程执行完任务


2主要方法:

public void await() throws InterruptedException { };   //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { };  //将count值减1

案例:
public class Test {
     public static void main(String[] args) {   
         final CountDownLatch latch = new CountDownLatch(2);
 
         new Thread(){
             public void run() {
                 try {
                     System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                    Thread.sleep(3000);
                    System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();
 
         new Thread(){
             public void run() {
                 try {
                     System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                     Thread.sleep(3000);
                     System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                     latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();
 
         try {
             System.out.println("等待2个子线程执行完毕...");
            latch.await();
            System.out.println("2个子线程已经执行完毕");
            System.out.println("继续执行主线程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
     }
}

总结:从两个案例中还是可以看出两个的用途还有区别的,一个可以多次设置屏障等待,一个值能一次.而CountDownLatch主要是针对指定线程,去等待其他先,CyclicBarrier是多个线程没有指定线程,哪个线程先到屏障点,该线程就先等待,当所有线程都完成了,那在唤醒等待线程去继续运行

两个类主要的方法都使用的是AQS类里面的方法.以后可详细说明,待后面学习.



猜你喜欢

转载自blog.csdn.net/zxf_0601/article/details/80185589