场景一:假如APP需要访问两个接口得到数据,在两个接口数据返回时再进行操作下一步。

主线程等待两个子线程完成以后继续,但是主线程等待不是卡机了啊….?

解决方案:三个线程,两个线程同时执行,一个线程等待,先完成的等待未完成的一个,直到都完成了才执行等待的线程,

代码

final int count = 2;
        final CountDownLatch countDownLatch = new CountDownLatch(count);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("small", "我是线程3,我在等待");
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e("small", "他们都完成了,执行了线程3");
            }
        }).start();
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("small", "我是线程" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e("small", "线程" + Thread.currentThread().getName() + "完成了");
                    countDownLatch.countDown();
                }
            }).start();

执行结果

android 协程 并发 android 多线程同步_i++

CountDownLatch其实它就是一个计数器,await()是等待计时器为0后才执行下去,countDown()是使计数器减一。

场景二:假如产品拿着刀来说,我要请求刚才两个接口,请求完后得到两个接口数据,再一起执行不同的操作。

麻蛋,上面不是说了吗,我tm开四个线程,两个请求两个等待不就行了?呵呵哒,天真烂漫,上面所说的计数器作用效果只有一次,那就是说只能用于一个线程里面。我能怎么办,我也很绝望啊。来来来,装逼的时候又到了。

final int count = 2;
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        for (int i = 0; i < count; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("small", "线程" + Thread.currentThread().getName() + "执行");
                    try {
                        Log.e("small", "线程" + Thread.currentThread().getName() + "请求数据");
                        Thread.sleep(3000);
                        Log.e("small", Thread.currentThread().getName() + "请求数据成功");
                        cyclicBarrier.await();
                    } catch (InterruptedException E) {
                        E.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    Log.e("small", "线程" + Thread.currentThread().getName() + "继续执行");
                }
            }).start();

又是很简单的代码

动图完事

android 协程 并发 android 多线程同步_i++_02


1. CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。

2. CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。

3. CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

场景三:面试官问你,怎么让两个线程依次执行?

是不是脱口而出在一个线程执行完后在线程里再开一个线程~,~,你看面试官会不会打死你。这更加简单,直接上代码吧。

android 协程 并发 android 多线程同步_主线程_03

搞掂
情景四:小明打了老王一巴掌,老王打回他,小明又打老王一巴掌,循环如此~,~

我勒个擦,这么奇葩。还好,上有政策下游对策。

final Object object = new Object();

final Thread threadA = new Thread(new Runnable() {
        @Override
        public void run() {
            int i = 0;
            while (i < 5) {
                synchronized (object) {
                    try {
                        System.out.println("小明打了老王一巴掌");
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                }
            }
        }
    });
    Thread threadB = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                int i = 0;
                while (i < 5) {
                    synchronized (object) {
                        System.out.println("老王打了小明一巴掌");
                        object.notify();
                        i++;
                    }
                    Thread.sleep(1500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    threadA.start();
    threadB.start();

android 协程 并发 android 多线程同步_android 协程 并发_04

CountDownLatch 和CyclicBarrier的不同

CountDownLatch 适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch 的主要场景;CyclicBarrier 用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。另外,CyclicBarrier 的循环特性和构造函数所接受的 Runnable 参数也是 CountDownLatch 所不具备的。