Java中join()方法原理及使用教程

简介

前面几篇文章讲解了wait()方法之后,我们再来讲讲join()方法,因为join()方法就是通过wait()方法实现的。

一.join()方法的作用

作用:让主线程等待(WAITING状态),一直等到其他线程不再活动为止。

join在英语中是“加入”的意思,join()方法要做的事就是,当有新的线程加入时,主线程会进入等待状态,一直到调用join()方法的线程执行结束为止。

join用法示例:
ublic static void main(String[] args) {
    Runnable runnable = new Runnable() {
			@Override
			public void run() {
				System.out.println("子线程执行");
			}
		};
    Thread thread1 = new Thread(runnable);
    Thread thread2 = new Thread(runnable);
    thread1.start();
    thread2.start();
    try {
        //主线程开始等待子线程thread1,thread2
        thread1.join();
        thread2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    //等待两个线程都执行完(不活动)了,才执行下行打印
  `  System.out.println("执行完毕")`;;
}

执行分析:代码会在thread1和thread2执行完后,才会执行System.out.println("执行完毕");

join()方法的第一种等效写法

其中,这两行代码

thread1.join();
thread2.join();

可以替换为:

while (thread1.isAlive() || thread2.isAlive()) {
    //只要两个线程中有任何一个线程还在活动,主线程就不会往下执行
}

这两种写法作用一样。

二.join源码分析

join()方法代码是通过java代码实现的,代码如下:

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) {
        // 关键实现在此行,通过wait方法永久等待。
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

join()方法的两种等效写法

源码中:

 while (isAlive()) {
            wait(0);
        }

这就是为什么线程会一直等待,因为它调用的就是wait()方法呀。

关于wait()方法的介绍,请看《Java多线程wait()和notify()系列方法使用教程(内涵故事)》,此篇文章有详细讲解。

join()方法的第二种等效写法

所以join()方法又等同于以下代码:

synchronized(thread1)){
    thread1.wait();
}

源码中的疑问?

join()方法是用wait()方法实现,但为什么没有通过notify()系列方法唤醒呀,如果不唤醒,那不就一直等待下去了吗?

原因是:在java中,Thread类线程执行完run()方法后,一定会自动执行notifyAll()方法

详细参考文章《Java多线程中notifyAll()方法使用教程》中的第三部分“三.关于notifyAll()非常重要的隐藏知识点”,这篇文章写了详细解释。

三.使用join方法时,如何处理中断

当主线程中断时,最稳妥的方式是让子线程也中断(传递中断),这样就维护了线程间数据的一致性。

我们在子线程中中断主线程,然后当主线程执行thread1.join()方法时,就会抛出异常,异常原因是主线程已经被中断了,所以此行代码不能继续执行了。此时,最优秀的做法是把主线程的中断状态传递给子线程,即在catch()语句中,执行thread1.interrupt(),这样此线程也会中断,维护了多线程之间的数据一致性。

代码演示:
public static void main(String[] args) {
		// 获取主线程
		Thread mainThread = Thread.currentThread();
		Thread thread1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					// 在子线程中,让主线程中断
					System.out.println("thread1已启动,在thread1的run方法中,让主线程中断停止了");
					mainThread.interrupt();
					TimeUnit.SECONDS.sleep(4);
					System.out.println("thread1的run方法运行结束");
				} catch (InterruptedException e) {
					System.out.println("子线程开始响应中断,抛出中断异常说明成功中断");
				}
			}
		}, "thread1");
		thread1.start();
		try {
			// 主线程在等待子线程执行结束后,再执行后续代码。如果主线程在等待时被打断,那thread1.join()会抛出异常,
			// 此时正确的做法是在catch语句中将中断传递给thread1,让thread1也中断,保证多个线程执行的一致性;
			// 若不手动终止thread1,则thread1会继续执行,可能会造成一些数据同步上的问题。
			thread1.join();
		} catch (InterruptedException e) {
			System.out.println("主线程执行thread.join()方法时出现异常,提示主线程中断了(验证线程名:" + Thread.currentThread().getName() + ")");
			e.printStackTrace();
			thread1.interrupt();
		}
		System.out.println("main方法全部运行完毕");
	}

总结

本节介绍了join()方法的使用方法,分析了join()方法的源码,并且找到了两种join()方法的等效替换方法,然后我们讲解了使用join()方法时,讲解了为什么要响应主线程的中断,维护好多线程的数据一致性,并给出了代码示例。希望通过本文,可以彻底吃透join()方法。

  • 52
    点赞
  • 192
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 在 Java join 方法是用来等待一个线程终止的。你可以将 join 方法理解为“让我等着你结束,然后我再执行”。 你可以在一个线程对象上调用 join 方法,来等待这个线程终止。比如: ``` Thread t = new Thread(new Runnable() { public void run() { // 线程执行的任务 } }); t.start(); t.join(); // 等待 t 线程终止 ``` join 方法还有一个重载版本,允许你在等待一段时间后放弃等待: ``` t.join(1000); // 等待 t 线程终止,但最多等待 1000 毫秒 ``` 如果在指定的时间内 t 线程还没有终止,那么 join 方法就会立即返回。 另外,如果你不想等待线程 t 终止,你可以调用 t.isAlive() 方法来检查线程 t 是否还存活,如果存活就不用调用 join 方法了。 ### 回答2: 在Javajoin方法是Thread类提供的一个方法,它用于将一个线程加入到当前线程,等待该线程执行完毕后再继续执行。 join方法的调用者是当前线程,它用于管理其他线程的执行顺序。当调用某个线程的join方法时,当前线程将会进入阻塞状态,直到给定的线程执行完毕后才会继续执行。 join方法有两种重载方式: 1. join(): 这种方式没有参数,调用该方法的线程将会等待该线程执行完毕。 2. join(long millis): 这种方式接受一个参数,表示等待的时间(单位为毫秒)。如果在指定的时间内线程没有执行完毕,当前线程将会继续执行。 使用join方法可以方便地控制多个线程的执行顺序。例如,如果有两个线程t1和t2,我们可以通过调用t1.join()来确保t1执行完毕后再执行t2。 需要注意的是,join方法可能会抛出InterruptedException异常,这是因为线程在等待的过程可能会被中断。当出现这种情况时,我们可以根据实际情况进行处理,例如可以选择重新进行等待或者直接抛出异常。 总之,join方法Java用于管理线程执行顺序的重要方法。它可以让线程按照我们预期的方式执行,提高线程的可控性和可靠性。 ### 回答3: 在Javajoin方法是Thread类的一个方法,用于等待一个线程的终止。 当调用一个线程对象的join方法时,当前线程将被阻塞,直到被调用join方法的线程执行完毕才能继续执行。 join方法有两种重载形式: 1. join():等待被调用线程执行完毕。 2. join(long millis):等待被调用线程执行一定的时间。 join方法常用于需要等待子线程执行完毕后再执行的场景,特别是在主线程等待子线程的结果返回的情况。通过join方法,我们可以确保主线程在子线程完成后再继续执行。 当一个线程被调用join方法后,其他所有线程都会被阻塞,直到被调用join方法的线程执行完毕。这种阻塞是无法被中断的,也就是说其他线程无法通过中断被调用join方法的线程来解除阻塞状态。 如果被调用join方法的线程在执行过程抛出了异常,那么调用join方法的线程不会再等待,直接返回,继续执行自己的任务。 需要注意的是,如果调用join方法的线程已经处于终止状态,那么调用join方法的效果就相当于没有调用join方法一样,即调用线程不会被阻塞。 总之,join方法是用于等待一个线程的终止的方法,主要用于协调多个线程的执行顺序和获取子线程的结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值