线程的合并

线程的合并

在Java中,join()方法是Thread类中的一个方法,它允许一个线程等待另一个线程完成执行后再继续执行。
具体来说,当一个线程调用另一个线程的join()方法时,它会暂停自己的执行,直到被调用的线程执行完毕或者超时。

  1. join()方法是一个实例方法。(不是静态方法)

  2. 假设在main方法(main线程)中调用了 t.join(),后果是什么?

    • t线程合并到主线程中。主线程进入阻塞状态。直到 t 线程执行结束。主线程阻塞解除。
  3. 和sleep方法有点类似,但不一样:

    • 第一:sleep方法是静态方法,join是实例方法。
    • 第二:sleep方法可以指定睡眠的时长,join方法不能保证阻塞的时长。
    • 第三:sleep和join方法都是让当前线程进入阻塞状态。
    • 第四:sleep方法的阻塞解除条件?时间过去了。 join方法的阻塞解除条件?调用join方法的那个线程结束了。

一、join()方法的使用方式

  1. 基本用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Thread thread = new Thread(() -> {
    // 线程执行的代码
    });

    thread.start(); // 启动线程

    try {
    thread.join(); // 等待thread线程执行完毕
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    // 在这里可以确保thread线程已经执行完毕

    在上面的例子中,调用了thread.join()方法,主线程将会等待thread线程执行完毕后再继续执行。

  2. 超时等待

    1
    2
    3
    4
    5
    try {
    thread.join(1000); // 等待thread线程最多1秒,超时后会继续执行
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    可以通过join(long millis)方法指定一个超时时间,单位为毫秒。如果指定时间内线程未执行完毕,则超时后会继续执行。

  3. 中断处理

    1
    2
    3
    4
    5
    6
    try {
    thread.join();
    } catch (InterruptedException e) {
    // 处理中断异常
    e.printStackTrace();
    }

    join()方法会抛出InterruptedException异常,通常在等待的线程被中断时会触发此异常。因此,在调用join()时需要考虑如何处理中断异常。

二、join()方法的应用场景

  • 线程顺序执行:当需要确保线程按照某种顺序执行时,可以在一个线程中调用另一个线程的join()方法。

  • 任务依赖:当一个任务依赖于另一个任务的结果时,可以在等待另一个任务完成后再进行处理。

  • 协同工作:多个线程协同工作时,有时需要等待某个关键线程完成某个阶段后再进行下一步操作。

三、示例代码

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.camellia.thread.ThreadMerging;

import org.junit.jupiter.api.Test;

/**
* 线程合并
* 1. 调用join()方法完成线程合并。
*
* 2. join()方法是一个实例方法。(不是静态方法) t.join
*
* 3. 假设在main方法(main线程)中调用了 t.join(),后果是什么?
* t线程合并到主线程中。主线程进入阻塞状态。直到 t 线程执行结束。主线程阻塞解除。
*
* 4. t.join()方法其实是让当前线程进入阻塞状态,直到t线程结束,当前线程阻塞解除。
*
* 5. 和sleep方法有点类似,但不一样:
* 第一:sleep方法是静态方法,join是实例方法。
* 第二:sleep方法可以指定睡眠的时长,join方法不能保证阻塞的时长。
* 第三:sleep和join方法都是让当前线程进入阻塞状态。
* 第四:sleep方法的阻塞解除条件?时间过去了。 join方法的阻塞解除条件?调用join方法的那个线程结束了。
*/
public class ThreadMergingTest {

@Test
public void testJoin1() throws InterruptedException {
Thread thread = new MyThread();
thread.start();
System.out.println("main begin");
// 合并线程,thread合并到main线程中。main线程受到阻塞(当前线程受到阻塞),thread线程继续执行,直到thread线程结束。main线程阻塞解除(当前线程阻塞解除)。
thread.join();
// 主线程
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "==>" + i);
}
System.out.println("main over");
}

@Test
public void testJoin2() throws InterruptedException {
Thread thread = new MyThread();
thread.start();
System.out.println("main begin");
// 以下代码表示 thread 线程合并到 当前线程,合并时长 5 毫秒,阻塞当前线程 5 毫秒。
thread.join(5);
// 主线程
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "==>" + i);
}
System.out.println("main over");
}

@Test
public void testJoin3() throws InterruptedException {
Thread thread = new MyThread();
thread.start();
System.out.println("main begin");
// 想让当前线程受阻10秒,但不一定,如果在指定的阻塞时间内,thread线程结束了。当前线程阻塞也会解除。和sleep有区别。
thread.join(1000 * 10);
// 主线程
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "==>" + i);
}
System.out.println("main over");
}
}


class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "==>" + i);
}
}
}