高并发编程-Thread#join方法的使用及使用场景分析

举报
小工匠 发表于 2021/09/11 00:14:18 2021/09/11
【摘要】 文章目录 含义方法及示例void join()void join(long millis)join(long millis, int nanos) 使用场景分析 含义 翻看下源...

在这里插入图片描述

在这里插入图片描述

含义

翻看下源码的注释: Waits for this thread to die
我们翻越下官网中Thread 关于join的说明 乍理解起来有点晦涩, 简单来说: 等待该线程终止. 需要明确的是主线程等待子线程(假设有个子线程thread)的终止。即在主线程的代码块中,如果碰到了thread.join()方法,此时主线程需要等子线程thread结束了(Waits for this thread to die.),才能继续执行thread.join()之后的代码块

后面会有示例说明


方法及示例

在这里插入图片描述

void join()

重点看注释 ,这里就不多说了。

package com.artisan.test;

import java.util.stream.IntStream;

public class JoinThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " 主线程 start");
        System.out.println("------------------------------------------------");

        // 定义一个线程
        Thread t = new Thread(() -> {
            // 打印 1 到 10 的数字
            IntStream.range(0, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + ">>>>>>" + i));
            Optional.of(Thread.currentThread().getName() + " 打印完毕").ifPresent(System.out::println);

        },"artisan-thread");
        // 启动线程
        t.start();
        // 在主线程中 ,开启了一个新的线程t ,调用 t.join方法,确保该线程执行结束后,才会继续执行主线程中剩下的逻辑
        t.join();

        Optional.of("------------------------------------------------").ifPresent(System.out::println);
        System.out.println(Thread.currentThread().getName() + " 主线程 over");
    }
}



  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

输出:

在这里插入图片描述

可以看到 ,调用了 t.join() 后, 主线程main线程,一直等到该线程执行结束后,才继续执行main线程自己剩下的业务逻辑。


我们继续来看下在main线程开启多个线程,分别join的情况

package com.artisan.test;

import java.util.Optional;
import java.util.stream.IntStream;

public class JoinThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " 主线程 start");
        System.out.println("------------------------------------------------");

        // 定义一个线程
        Thread t = new Thread(() -> {
            // 打印 1 到 10 的数字
            IntStream.range(0, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + ">>>>>>" + i));
            Optional.of(Thread.currentThread().getName() + " 打印完毕").ifPresent(System.out::println);
        },"artisan-thread");

        Thread t2 = new Thread(() -> {
            // 打印 1 到 10 的数字
            IntStream.range(0, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + ">>>>>>" + i));
            Optional.of(Thread.currentThread().getName() + " 打印完毕").ifPresent(System.out::println);
        },"littleART-thread");

        // 启动线程
        t.start();
        t2.start();
        // 在主线程中 ,开启了一个新的线程t ,调用 t.join方法,确保该线程执行结束后,才会继续执行主线程中剩下的逻辑
        t.join();
        t2.join();


        Optional.of("------------------------------------------------").ifPresent(System.out::println);
        System.out.println(Thread.currentThread().getName() + " 主线程 over");
    }
}



  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

日志输出如下

在这里插入图片描述

可以看到 , main线程依然是等待t1和t2执行完以后才继续执行自己的逻辑,但是t1 和 t2 是交替执行的,主要取决于CPU的调度,这是正确的。


void join(long millis)

等待多少毫秒后,如果未完成,继续当前线程的任务。

举个例子来演示下

package com.artisan.test;

import java.util.Optional;
import java.util.stream.IntStream;

public class JoinThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " 主线程 start");
        System.out.println("------------------------------------------------");

        // 定义一个线程
        Thread t = new Thread(() -> {
            try {
                // 先休眠10S,再输出 0 到 9
                Thread.sleep(10_000);
                
                Optional.of(Thread.currentThread().getName() + " 休眠结束...继续干活").ifPresent(System.out::println);

                IntStream.range(0, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + ">>>>>>" + i));
                Optional.of(Thread.currentThread().getName() + " 打印完毕").ifPresent(System.out::println);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"artisan-thread");

        t.start();
        // t 线程等待 1000毫秒 即 1秒,如果未完成,则不等待,继续主线程中逻辑
        t.join(1000);


        Optional.of("---------------等待1秒结束,继续主线程的业务----------------").ifPresent(System.out::println);
        System.out.println(Thread.currentThread().getName() + " 主线程 over");
    }
}



  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

输出:

在这里插入图片描述

可以看到 线程t在调用 join(1000),等待1秒后,该任务没有完成,主线程继续执行剩下的逻辑, 执行完以后没有退出 是因为t这个线程是user thread ,而不是daemon thread, 所以还是会继续执行的。


join(long millis, int nanos)

这个其实和 join(long milli)一样 ,只是等待的时间加上纳秒 wait for specified time (milliseconds + nanos). 没啥好演示的了。。。


使用场景分析

假设主线程中开启了N个子线程,多个子线程可能有多个任务处理,假设业务要求当主线需要等待子线程处理完以后才能继续剩下的业务逻辑,这个时候如果不是用J.U.C包中的类,用原生的线程中提供的方法来处理的话,就是join了。

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/100944145

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。