【多线程 七】 线程间通信之join()

本文详细解析了Java多线程中的join方法,它用于让主线程等待子线程执行完成后再继续执行。通过代码示例展示了join方法的使用,分析了其工作原理,并对比了join与sleep方法的区别。同时,解释了join方法可能导致后续代码提前运行的情况。
摘要由CSDN通过智能技术生成
前言

前面我们全面介绍了多线程间是如何通信的: 地址链接,接下来我们详细的介绍join方法,它有什么作用解决了什么问题。

1、引入

在多线程的环境中,如果要想实现这样一个效果:子线程的执行过程中比较耗费时间,但是我想 主线程在子线程执行完之后再执行,这时候有一个方法它可以解决此问题,那就是join方法
在这里插入图片描述

2、代码展示
2.1 创建一个线程MyThread
public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            int secondValue = (int) (Math.random() * 10000);
            System.out.println(secondValue);
            Thread.sleep(secondValue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
2.2 主程序
public class Test {
    public static void main(String[] args) {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            myThread.join();
            System.out.println("当线程myThread执行完毕后再执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
2.3 运行结果

在这里插入图片描述

2.4 分析

方法join的作用是使所属的线程对象x( 此代码中的myThread)正常执行run()方法中的任务,而使当前线序Z (此代码中的Main线)程进行无期限的阻塞就,等待线程x销毁后再继续执行线程。

2.5解读疑问——为什么join阻塞的是主(父)线程

这个问题困扰了我一会,且看join源码,其实它就是wait,wait的作用是释放对象锁,释放CUP资源,使当前线程阻塞,而当前线程就是main线程,当时让我疑惑是因为我把myThread当成了当前线程,其实myThread就是一个线程对象,是在主线程进行实例化的,所以main线程才是阻塞的对象,也就是join阻塞的是主线程。

   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); //如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。 
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
3 join(long)与sleep(long)的区别

结论先行: join释放锁,sleep不释放锁

分析:首先刚才上面咱们看了源码,join的底层是用wait实现的,wait释放锁,所以join也就是释放锁。sleep是不释放锁的,它一直使当前线程阻塞,直到时间到才会释放锁。

4 方法join()后面的代码提前运行的原因分析

前提:方法join()大部分是先运行的(java多线程核心编程技术一书中给的结论),就是说它先抢到线程锁,然后再快速进行释放,因为源码中wait(0)表示的事无限阻塞。

分析java(long)导致后面的代码提前运行:

部分代码:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ThreadB threadB=new ThreadB();
        ThreadA threadA=new ThreadA(threadB);
        threadA.start();
        threadB.start();
        threadB.join(2000);
        System.out.println("                 main end "+System.currentTimeMillis());
    }
}

threadB.join() 先抢到threadB锁,然后快速释放,此时A抢到锁,执行完,此时threadB.join(2000)(代表主线程,上面解释过了)和线程threadB进行争抢锁,此时就会出现不同的结果,可能join(2000)先抢到线程,然后后边的代码就行了,这也就导致后面的代码提前运行。也可能threadB先抢到锁,执行完,再执行主线程后边的代码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>