资讯专栏INFORMATION COLUMN

一起学并发编程 - 线程Join分析

happen / 2967人阅读

摘要:当时,会进入循环,系统会判断主线程是否处于活跃状态,如果处于活跃状态,主线程就会不停的等待。

由于前段时间比较忙,线程这快学习停滞了,只能利用周日的时间来写写博客了,多线程Join方法的作用就是把指定的线程加入到当前线程,让主线程等待子线程结束之后才能继续运行,从而完成同步操作

介绍

join() 的作用:让主线程等待子线程结束之后才能继续运行,首先先来看下以采集为案例的代码,统计采集所消耗的时长

需求:当所有线程任务执行完毕,统计最终消耗时长

public class ThreadJoin {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        Thread t1 = new Thread(new CaptureRunnable("M1", 5_000L));
        Thread t2 = new Thread(new CaptureRunnable("M2", 3_000L));
        Thread t3 = new Thread(new CaptureRunnable("M3", 2_000L));
        t1.start();
        t2.start();
        t3.start();
        System.out.println("采集完成,消耗 " + (System.currentTimeMillis() - startTime));
    }
}

class CaptureRunnable implements Runnable {
    private String machineName;//采集任务名
    private Long spendTime;//采集工作消耗时长
    public CaptureRunnable(String machineName, Long spendTime) {
        this.machineName = machineName;
        this.spendTime = spendTime;
    }
    @Override
    public void run() {
        try {
            System.out.println(machineName + "开始采集");
            Thread.sleep(spendTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ThreadJoin的代码中,我们创建了主线程main,和实现了RunnableCaptureRunnable子线程,运行main方法,可以看到在未使用join()的情况下,统计结果并不理想,正确输出应该是5000毫秒以上

采集完成,消耗 1
M1开始采集
M2开始采集
M3开始采集
使用join

start方法下添加join操作,运行main方法,发现不管那个线程先执行,结果都是5000毫秒以上,因为主线程main接收到了M1,M2,M3三个线程的join指令,这个时候主线程则会处于阻塞状态,直到子线程执行完毕后才会继续执行下去...

t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
M2开始采集
M1开始采集
M3开始采集
采集完成,消耗 5001
部分join

去掉M1线程调用的join,然后运行main方法,从日志输出中可以发现,main会等待M2,M3执行完毕后才会继续执行下去

M1开始采集
M3开始采集
M2开始采集
采集完成,消耗 3001
源码分析
public final void join() throws InterruptedException {
    join(0);
}

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

说明

从代码中,我们可以发现。当millis==0时,会进入while(isAlive())循环,系统会判断主线程是否处于活跃状态,如果处于活跃状态,主线程就会不停的等待。

问题

为什么子线程调用join()阻塞的却是主线程呢?join()方法中的isAlive()应该是判断子线程是否处于活跃的状态,对应的wait(0)也应该是让子线程等待才对

答案

首先从源码中我们可以发现它是被synchronized修饰的方法,当前线程的对象调用join后,其实获取到了子线程M1,M2,M3的锁,当子线程锁释放后才会继续执行主线程的操作

使用jvisualvm分析器,可以发现Thread-1-3与主线程main,处于等待的是主线程,子线程因为调用了sleep处于休眠状态(为了演示耗时操作)

- 说点什么

全文代码:https://git.oschina.net/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter3

个人QQ:1837307557

battcn开源群(适合新手):391619659

微信公众号:battcn(欢迎调戏)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67631.html

相关文章

  • 一起并发编程 - 优雅关闭

    摘要:文本将介绍两种可以优雅的终止线程的方式第一种在多线程模式中有一种叫两步终止的模式可以优雅的终止线程,这种模式采用了两个步骤来终止线程,所以叫两步终止模式。 Java中原来在Thread中提供了stop()方法来终止线程,但这个方法是不安全的,所以一般不建议使用。文本将介绍两种可以优雅的终止线程的方式... 第一种 在JAVA《Java多线程模式》中有一种叫Two-Phase Term...

    曹金海 评论0 收藏0
  • 一起并发编程 - 处理异常中止的线程

    摘要:在之前,不能为线程单独设置或指定一个默认的,为了设置,需要继承并覆写方法。幸运的是后线程提供了一个方法,用来捕获并处理因线程中抛出的未知异常,以避免程序终止。 在单线程的开发过程中,通常采用try-catch的方式进行异常捕获,但是这种方式在多线程环境中会显得无能为力,而且还有可能导致一些问题的出现,比如发生异常的时候不能及时回收系统资源,或者无法及时关闭当前的连接... 概述 Ja...

    zacklee 评论0 收藏0
  • java并发编程习之线程的生命周期-join(四)

    摘要:定义等待该线程终止,比如线程调用了线程的,那么线程要等到线程执行完后,才可以继续执行。 定义 等待该线程终止,比如A线程调用了B线程的join,那么A线程要等到B线程执行完后,才可以继续执行。 示例 public class JoinDemo { static class JoinThread1 implements Runnable { Thread thre...

    xavier 评论0 收藏0
  • java并发编程习之Fork/Join 框架-基本概念(一)

    摘要:思想把大任务分割成多个小任务,再把小任务的结果汇总,最终得到大任务的结果。当一个线程执行完当前队列的任务时,他就会去窃取其他队列的任务来执行。当双端队列只有一个任务时,线程之间会竞争。 思想 把大任务分割成多个小任务,再把小任务的结果汇总,最终得到大任务的结果。 步骤如下: 任务分割 结果汇总 示例图 showImg(https://segmentfault.com/img/bVb...

    hikui 评论0 收藏0
  • 一起并发编程 - 死锁跟踪分析

    摘要:上一章介绍过关键字,使用它可以给程序互斥部分加上一把锁从而达到同步的效果,但错误的用法会导致多个线程同时被阻塞死锁死锁多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 上一章介绍过synchronized关键字,使用它可以给程序互斥部分加上一把锁从而达到同步的效果,但错误的用法会导致多个线程同时被阻塞.... 死锁 死锁...

    ACb0y 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<