java如何实现子线程执行完毕后再执行主线程

子线程常用来执行耗时任务,有时主线程需要子线程执行完毕后的结果再执行,现在来探讨实现该场景的几种实现方式

一、join()

说明:Thread中的join()方法就是同步,它使得线程之间由并行执行变为串行执行。

测试代码如下:

object ThreadTest {

    @JvmStatic
    fun main(args: Array<String>) {
        val t = Thread(SubThread())
        t.start()

        mainWork()

        t.join()

        println("Now all thread done!")
    }


    // 子线程
    class SubThread : Runnable {
        override fun run() {
            println("Sub thread is starting!")

            try {

                Thread.sleep(5000L)

            } catch (e: InterruptedException) {

                e.printStackTrace()

            }

            println("Sub thread is stopping!")
        }

    }

    // 主线程
    private fun mainWork() {
        println("Main thread start work!")
        //sleep
        Thread.sleep(2000L)
        println("Main Thread work done!")
    }

}

二、CountDownLatch

说明:CountDownLanch 是一个倒数计数器, 给一个初始值(>=0), 然后每一次调用countDown就会减1, 这很符合等待多个子线程结束的场景: 一个线程结束的时候, countDown一次, 直到所有的线程都countDown了 , 那么所有子线程就都结束了。

      常用方法:

       await: 会阻塞等待计数器减少到0位置. 带参数的await是多了等待时间.

  countDown: 将当前的计数减1

  getCount(): 返回当前的计数

  显而易见, 我们只需要在子线程执行之前, 赋予初始化countDownLanch, 并赋予线程数量为初始值.

  每个线程执行完毕的时候, 就countDown一下.主线程只需要调用await方法, 可以等待所有子线程执行结束。

  示例:

object CountDownLatchTest {

    @JvmStatic
    fun main(args: Array<String>) {
        //定义线程数
        val subThreadNum = 5
        //取得一个倒计时器,从5开始
        val countDownLatch = CountDownLatch(subThreadNum)
        //依次创建5个线程,并启动
        for (i in 0 until subThreadNum) {
            Thread(SubThread(2000L * (i + 1), countDownLatch)).start()
        }

        mainWork()

        // 等待所有的子线程结束
        countDownLatch.await()
        println("Now all thread done!")

        /**
         * 运行结果
         * Main thread start work!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Main Thread work done!
        Now all thread done!
         */
    }


    // 子线程
    class SubThread(var workTime:Long,var countDownLatch: CountDownLatch) : Runnable {
        override fun run() {
            println("Sub thread is starting!")

            try {

                Thread.sleep(workTime)


            } catch (e: InterruptedException) {

                e.printStackTrace()

            }finally {
                countDownLatch.countDown()
            }

//            println("Sub thread is stopping!")
        }

    }



    // 主线程
    private fun mainWork() {
        println("Main thread start work!")
        //sleep
        Thread.sleep(2000L)
        println("Main Thread work done!")
    }

}

但是有一点有意思的现象,mainwork的“Main Thread work done!”总是在所有的子线程执行完毕后才执行,即使他的休眠时间比有的子线程时间少,这点令人不解。

三、CyclicBarrier

示例:

object CyclicBarrierTest {

    @JvmStatic
    fun main(args: Array<String>) {
        //定义线程数
        val subThreadNum = 5
        //取得一个倒计时器,从5开始
        val cyclicBarrier = CyclicBarrier(subThreadNum)
        //依次创建5个线程,并启动
        for (i in 0 until subThreadNum) {
            Thread(SubThread(2000L * (i + 1), cyclicBarrier)).start()
        }

        mainWork()

        // 等待所有的子线程结束
        cyclicBarrier.await()
        println("Now all thread done!")

        /**
         * 运行结果
         * Main thread start work!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Sub thread is starting!
        Main Thread work done!
        Now all thread done!
         */
    }


    // 子线程
    class SubThread(var workTime:Long,var cyclicBarrier: CyclicBarrier) : Runnable {
        override fun run() {
            println("Sub thread is starting!")

            try {

                Thread.sleep(workTime)


            } catch (e: InterruptedException) {

                e.printStackTrace()

            }finally {
                // 到达屏障
                cyclicBarrier.await()
            }

//            println("Sub thread is stopping!")
        }

    }



    // 主线程
    private fun mainWork() {
        println("Main thread start work!")
        //sleep
        Thread.sleep(2000L)
        println("Main Thread work done!")
    }

}

说明:CountDownLatch和CyclicBarrier有什么区别呢?

他们的区别:CountDownLatch只能使用一次,而CyclicBarrier方法可以使用reset()方法重置,所以CyclicBarrier方法可以处理更为复杂的业务场景。

四、Future

说明:使用并发包下面的Future模式.

  Future是一个任务执行的结果, 他是一个将来时, 即一个任务执行, 立即异步返回一个Future对象, 等到任务结束的时候, 会把值返回给这个future对象里面. 我们可以使用ExecutorService接口来提交一个线程.(注意:Future.get()为一个阻塞方法)

  示例:

object FutureTest {

    @JvmStatic
    fun main(args: Array<String>) {
        // 创建一个为1的线程池
        val tp = Executors.newFixedThreadPool(1)
        val t = Thread(SubThread())
        val future = tp.submit(t)
        mainWork()
        // 阻塞,等待子线程结束
        future.get()
        println("Now all thread done!")
        // 关闭线程池
        tp.shutdown()
    }

    // 子线程
    class SubThread : Runnable {
        override fun run() {
            println("Sub thread is starting!")

            try {

                Thread.sleep(5000L)

            } catch (e: InterruptedException) {

                e.printStackTrace()

            }

            println("Sub thread is stopping!")
        }

    }



    // 主线程
    private fun mainWork() {
        println("Main thread start work!")
        //sleep
        Thread.sleep(2000L)
        println("Main Thread work done!")
    }

}

总结:

以上几种方式根据业务场景和需求选用合适的同步方式

参考文章:

问题:如何实现java主线程等待子线程执行完毕之后再执行?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值