美文网首页
主线程等待

主线程等待

作者: 一直在路上_求名 | 来源:发表于2020-05-30 22:09 被阅读0次

场景介绍

在实际的工作过程中,为了减少用户的等待时间,通常会使用多线程去并行处理相关任务。主任务线程等待其他并行任务处理完成后,获取执行的结果,经过相关处理,返回给用户。这种方式是多线程在程序中主要的使用方式,因此这就要求主线程必须等待任务线程的执行,然后汇总结果。

实现方法

join方法

在 CountDownLatch 类未出现之前要实现主线程等待只能使用 join 方法(这样说有点绝对,因为 Future 的 get 方法也能实现闭锁的功能,但是需要自己将其缓存后再去循环处理,不是使用 JDK 所提供的方法了)。join 方法和之前介绍的方法不同,它是线程 Thread 类的方法,它没有入参也没有返回值。

示例代码
public static void main(String[] args) throws InterruptedException {
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1 end");
        });
        Thread t2 = new Thread(() -> {
            System.out.println("t2 start");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2 end");
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("main end");
    }              

如上代码中,创建了两个子线程 t1 和 t2, 然后分别启动两个子线程并调用各自的 join 方法。方法执行后,会先执行两个子线程,执行完后才会执行主线程的打印任务。
执行过程为,当主线程执行到 t1.join() 的时候其会被阻塞,等待 t1 执行完后再执行 t2.join() 会再次被阻塞,等到 t2 执行完后,再执行主线程的打印任务。
需要注意的是,要先启动后再调用 join 方法才会有用,如果先调用 join 方法再启动是不会生效的。

CountDownLatch

上面我们介绍了通过使用线程类的 join 方法来让主线程等待,但是这个方法不够灵活,对实际工作的各种场景并不能完全满足,因此 JDK 提供了 CountDownLatch 类,可以让我们能更好的实现该功能。

示例代码
public static void main(String[] args) throws InterruptedException {
        System.out.println("main start");
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            try {
                System.out.println("t1 start");
                Thread.sleep(500);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }).start();
        new Thread(() -> {
            try {
                System.out.println("t2 start");
                Thread.sleep(1000);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }).start();
        countDownLatch.await();
        System.out.println("main end");
    }
}

如上代码中,创建了一个 CountDownLatch 对象,由于有两个子线程,所以构造函数传入的参数为2。然后创建了两个子线程,在各自的 finally 模块中调用 CountDownLatch 对象的 countDown 方法;分别启动两个子线程,最后由主线程调用 CountDownLatch 对象的 await 方法,并执行打印任务。
代码的执行过程为,在创建 CountDownLatch 对象时,构造方法传入了计数器数量2,主线程调用 CountDownLatch 对象的 await 方法时将会被阻塞,直到 CountDownLatch 对象中的计数器变为0,主线程才会返回,阻塞也就结束了。在子线程执行时,由于调用了 CountDownLatch 对象的 countDown 方法,每次调用计数器都会减1 ,两次调用后计数器变为0,主线程结束阻塞打印日志。
需要注意的是,CountDownLatch 对象的 await 方法被返回时,只需要 CountDownLatch 对象的计数器变为0即可,所以只需要调用 countDown 方法的次数为计数器的数量即可,并不需要各线程都执行完成,示例代码如下:

public static void main(String[] args) throws InterruptedException {
        System.out.println("main start");
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            try {
                System.out.println("t1 start");
                Thread.sleep(2000);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }).start();
        new Thread(() -> {
            try {
                System.out.println("t2 start");
                Thread.sleep(1000);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
                countDownLatch.countDown();
            }
        }).start();
        countDownLatch.await();
        System.out.println("main end");
    }

总结

1、join 方法是 Thread 类的方法,调用它时主线程会阻塞到调用它的线程执行完后才执行。
2、CountDownLatch 类是 JDK 专门提供的一个用来操作线程等待的类,它是使用计数器的方法,并不关心各线程是否执行完成,因此它更加的灵活。
3、由于在实际工作中,常常使用线程池来管理程序中的线程,因此使用 CountDownLatch 类来处理会更加灵活实用。

相关文章

  • CountDownLatch与CyclicBarrier

    CountDownLatch CountDownLatch这个类使一个线程等待其他线程完成各自的工作再执行,例如主...

  • caogao

    源码-ActivityThread.java 初始化主线程的Looper,主Handler。并使主线程进入等待接收...

  • iOS开发—GCD笔记

    多线程,主GCD 串行队列(Serial Dispatch Queue,等待现有处理结束) 并行队列�(Concu...

  • Java 实现子线程返回值的几种方法

    一、主线程等待法# 此方法就是让主现成空转,等待数据,耗费系统资源。 一、Thread join()方法,系统自...

  • 计数器:CountDownLatch,CountDownLatc

    计数器 CountDownLatch: 一个线程等待多个线程。 CyclicBarrier:多个线程相互等待,等待...

  • IOS 等待条件满足再向下执行但不主卡线程NSRunLoop

    IOS 等待条件满足再向下执行但不主卡线程NSRunLoop[https://www.cnblogs.com/io...

  • C++ 线程类thread

    c++ 线程类 thread 注:join 是线程等待,等待子线程结束后在继续执行;线程等待要用sleep_for...

  • C++同步并发操作

    何时需要线程同步 线程完成前,需要等待另一个线程执行 线程需要等待特定事件发生 线程等待某个条件变为true 线程...

  • Kotlin线程(4)线程管理

    等待线程结束 (join)线程让步 (yield)线程停止 一、等待线程结束   当一个线程调用其它线程(t1)的...

  • 三、线程间协调

    父线程开启、中断、等待子线程结束 阻塞等待获取异步线程的执行结果 等待-通知模型,条件不满足休眠等待 Synchn...

网友评论

      本文标题:主线程等待

      本文链接:https://www.haomeiwen.com/subject/fofhzhtx.html