java多线程--join函数

1. join()介绍

join() 定义在Thread.java中。

join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。这句话可能有点晦涩,我们还是通过例子去理解:

// 主线程
public class Father extends Thread {
    public void run() {
        Son s = new Son();
        s.start();
        s.join();
        ...
    }
}
// 子线程
public class Son extends Thread {
    public void run() {
        ...
    }
}<span style="font-family: 'Courier New' !important; font-size: 12px !important; line-height: 1.5 !important; color: rgb(0, 0, 0);"></span>

说明

上面的有两个类Father(主线程类)和Son(子线程类)。因为Son是在Father中创建并启动的,所以,Father是主线程类,Son是子线程类。

在Father主线程中,通过new Son()新建“子线程s”。接着通过s.start()启动“子线程s”,并且调用s.join()。在调用s.join()之后,Father主线程会一直等待,直到“子线程s”运行完毕;在“子线程s”运行完毕之后,Father主线程才能接着运行。 这也就是我们所说的“join()的作用,是让主线程会等待子线程结束之后才能继续运行”!

2. join()源码分析(基于JDK1.7.0_40)

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;
        }
    }
}<span style="font-family: 'Courier New' !important; font-size: 12px !important; line-height: 1.5 !important; color: rgb(0, 0, 0);"></span>

说明

从代码中,我们可以发现。当millis==0时,会进入while(isAlive())循环;即只要子线程是活的,主线程就不停的等待。

我们根据上面解释join()作用时的代码来理解join()的用法!

问题

虽然s.join()被调用的地方是发生在“Father主线程”中,但是s.join()是通过“子线程s”去调用的join()。那么,join()方法中的isAlive()应该是判断“子线程s”是不是Alive状态;对应的wait(0)也应该是“让子线程s”等待才对。但如果是这样的话,s.join()的作用怎么可能是“让主线程等待,直到子线程s完成为止”呢,应该是让"子线程等待才对(因为调用子线程对象s的wait方法嘛)"?

答案wait()的作用是让“当前线程”等待,而这里的“当前线程”是指当前在CPU上运行的线程。所以,虽然是调用子线程的wait()方法,但是它是通过“主线程”去调用的;所以,休眠的是主线程,而不是“子线程”!

3. join()示例

在理解join()的作用之后,接下来通过示例查看join()的用法。

// JoinTest.java的源码
public class JoinTest{ 

    public static void main(String[] args){
        try {
            ThreadA t1 = new ThreadA("t1"); // 新建“线程t1”

            t1.start();                     // 启动“线程t1”
            t1.join();                        // 将“线程t1”加入到“主线程main”中,并且“主线程main()会等待它的完成”
            System.out.printf("%s finish\n", Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } 

    static class ThreadA extends Thread{

        public ThreadA(String name){
            super(name);
        }
        public void run(){
            System.out.printf("%s start\n", this.getName()); 

            // 延时操作
            for(int i=0; i <1000000; i++)
               ;

            System.out.printf("%s finish\n", this.getName());
        }
    }
}<span style="font-family: 'Courier New' !important; font-size: 12px !important; line-height: 1.5 !important; color: rgb(0, 0, 0);"></span>

运行结果

t1 start
t1 finish
main finish<span style="font-family: 'Courier New' !important; font-size: 12px !important; line-height: 1.5 !important; color: rgb(0, 0, 0);"></span>

结果说明

运行流程如图

(01) 在“主线程main”中通过 new ThreadA("t1") 新建“线程t1”。 接着,通过 t1.start() 启动“线程t1”,并执行t1.join()。

(02) 执行t1.join()之后,“主线程main”会进入“阻塞状态”等待t1运行结束。“子线程t1”结束之后,会唤醒“主线程main”,“主线程”重新获取cpu执行权,继续运行。

时间: 2024-10-31 09:50:08

java多线程--join函数的相关文章

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

java多线程返回函数结果

两种方式:一种继承Thread类实现:一种通过实现Callable接口. 第一种方法: 因为实现Thread类的run方法自身是没有返回值的,所以不能直接获得线程的执行结果,但是可以通过在run方法里把最后的结果传递给实例变量,然后通过getXX方法获取该实例变量的值.继承实现的代码: [java] view plaincopy class RunThread extends Thread{ private String runLog; private BufferedReader br; {

java多线程join

目的:程序执行完任务后,再执行其他的任务. 实现原理: 使用Thread类的join()方法时.当一个线程对象的join()方法被调用是,调用它的线程将被挂起,直到这个线程对象完成它的任务. 代码:引用的java7并发编程实战手册示例代码 package com.packtpub.java7.concurrency.chapter1.recipe6.task; import java.util.Date; import java.util.concurrent.TimeUnit; /** * C

java_ java多线程返回函数结果

两种方式:一种继承Thread类实现:一种通过实现Callable接口. 第一种方法: 因为实现Thread类的run方法自身是没有返回值的,所以不能直接获得线程的执行结果,但是可以通过在run方法里把最后的结果传递给实例变量,然后通过getXX方法获取该实例变量的值.继承实现的代码: class RunThread extends Thread{ private String runLog; private BufferedReader br; { runLog = ""; } pu

java 多线程-join插队

join合并线程,插队线程,将此线程执行完成后,再执行其他线程,其他线程阻塞join是一个成员方法,必须通过Thread对象调用 public class n { public static void main(String[]args) throws InterruptedException { Thread t =new Thread(()-> { for(int i=0;i<5;i++) { System.out.println("a"+i); } }); t.sta

thread.join函数,java多线程中的join函数解析

join函数的作用,是让当前线程等待,直到调用join()的 线程结束或者等到一段时间,我们来看以下代码 1 package mian; 2 3 4 public class simpleplela { 5 static void threadMessage(String message) { 6 String threadName = 7 Thread.currentThread().getName(); 8 9 System.out.println(threadName+" "+m

java多线程控制函数setDaemon,join,interupt

1.setDeamon 设置线程为后台运行的函数 public class SetDaemon { public static void main(String[] args) throws InterruptedException { Thread tt=new Thread(new ThreadTest()); tt.setDaemon(true); //设置程序为后台运行 tt.start(); Thread.sleep(3); } } class ThreadTest implement

java多线程中join用法

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B. package com.wzs; /** * Java多线程中join用法 * * @author Administrator * */ public class JoinTest { public static void main(String[] args) { BThread bThread = new B

Python多线程的理解和使用(一)Threading中join()函数的理解

1. 多线程的概念 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理.用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度 程序的运行速度可能加快在一些等待的任务实现上如用户输入.文件读写和网络收发数据等,线程就比较有用了.在这种情况下我们可以释放一些珍贵的资源如内存占用等等.线程在执行过程中与进程还是有区别的.每个独立的线程有一个程序运行的入口.顺序执行序列和程序的出口.但是线程