在本教程中,我们将学习**如何连接两个线程以及为什么需要在Java中连接线程。**我们将详细探讨 ***Thread.join()***API和不同版本的API,并结合实际例子。
我们还将看到,在使用线程时,我们是如何陷入死锁状态的。 *join()*以及在我们的代码中有效使用它的方法。
目录
1.线程连接的介绍
线程 是一个轻量级的进程,它允许一个程序通过并行运行多个线程来更有效地运行。如果我们有一个要求,即第一个线程 必须等待第二个线程完成其执行,那么我们应该连接这两个线程。
让我们举个例子来更清楚地了解它。假设我们有3个线程,为一个婚姻应用程序执行3种不同的活动。

- 一旦婚礼卡打印活动完成,婚礼卡分发活动就开始,一旦我们确定了婚礼的地点,婚礼卡打印活动就开始。
- 我们可以说,在这种情况下,Thread-3必须等待Thread-2完成,而且Thread-2也必须等待Thread-1完成其执行。
- 线程-2必须调用Thread-1.join(),而线程-3必须调用Thread-2.join() ,这样他们就会等到另一个线程的完成。
2.JavaThread.join() API
join()方法使调用的Thread进入等待状态,直到被调用join()的Thread完成其执行。
- 一个线程
't1',想要等到另一个线程't2',完成它的执行,那么t1必须调用t2的*join()*方法。 - *t2.join()*由t1调用。
- 当t1执行t2.join()时,t1立即进入等待状态并继续等待,直到t2完成其执行并终止。
- 一旦t2完成了,那么只有t1继续执行它。

连接线程的生命周期
2.1 无超时的连接
默认的join()方法会让当前的线程无限期地等待,直到它所调用的线程完成。如果该线程被打断,它将抛出*InterruptedException。*
public final void join() throws InterruptedException
现在让我们来看看一个如何使用*join()* 方法的例子。
public class ChildThread extends Thread
{
public void run()
{
for(int i=1; i<=4; i++)
{
try{
Thread.sleep(500);
} catch(Exception e){
System.out.println(e);
}
System.out.println(“child thread execution - ” + i);
}
}
}
ChildThread th1 = new ChildThread();
// Starting child Thread
th1.start();
// main thread joining the child thread
th1.join();
// main Thread printing statements
System.out.println(“main thread completed”);
注意程序的输出。主线程正在调用子线程的*join()*方法并等待其完成,所以在调用*join()*之后。所以,子线程的所有语句都在主线程语句之前打印。
child thread execution - 1
child thread execution - 2
child thread execution - 3
child thread execution – 4
main thread completed
2.2 带超时的连接
join(long millis):它使当前线程 等待,直到它所调用的线程 完成,或者指定的时间(以毫秒为单位)已经过期。join(long millis, int nanos):它让当前的Thread等待,直到它被调用的Thread完成,或者指定的时间(毫秒+纳秒)已经过期。
public final synchronized void join(long millis) throws InterruptedException
public final synchronized void join(long millis, int nanos) throws InterruptedException
现在让我们通过一个例子来看看它是如何工作的。
// Creating child Thread Object
ChildThread th1 = new ChildThread();
// Starting child Thread
th1.start();
//main thread joining the child thread with 1000ms expiration time
th1.join(1000);
// main Thread printing statements
System.out.println(“main thread completed”);
当程序执行时,主线程最多会等待1000ms,之后会随时被调用。
child thread execution - 1
main thread completed
child thread execution - 2
child thread execution - 3
child thread execution - 4
3.中断一个已加入的线程
一个等待的线程 可以被另一个线程使用interrupt() 方法打断。 一旦等待中的Thread被中断,它就会立即从等待状态中出来 ,进入Ready/Runnable状态,并等待Thread Scheduler分配处理器以再次开始执行。
// Creating child Thread by extending Thread class
public class ThreadjoiningInterrupt extends Thread
{
// main Thread reference
private static Thread mt;
// Job of child Thread
public void run()
{
for (int i = 1; i <= 4; i++) {
// child Thread interrupting main Thread
mt.interrupt();
// child Thread prints statements
System.out.println("Child Thread Execution - " + i);
}
}
// main Thread Job
public static void main(String[] args)
{
// Setting main Thread object in 'mt' reference
Demo.mt = Thread.currentThread();
// Instantiating child Thread
Demo t1 = new Demo();
// Starting child Thread
t1.start();
try {
// main Thread calls join() on child Thread
t1.join();
} catch (InterruptedException ie) {
// catching Interrupted Exception
System.out.println("main Thread is interrupted");
}
// main Thread prints statements
for (int i = 1; i <= 4; i++) {
System.out.println("main Thread Execution - " + i);
}
}
}
注意程序的输出,一旦子线程中断了主线程,那么两个线程就同时执行了。
Child Thread Execution - 1
main Thread is interrupted
Child Thread Execution - 2
main Thread Execution - 1
main Thread Execution - 2
main Thread Execution - 3
main Thread Execution - 4
Child Thread Execution - 3
Child Thread Execution – 4
4.注意死锁
在使用join()方法时,我们必须小心,因为有时它可能导致死锁 的情况。如果**两个线程互相调用join()方法,那么这两个线程就会进入等待状态,永远等待对方。
同样地,如果一个线程由于错误地加入了自己,那么它将永远被阻塞,JVM将被关闭以恢复。
class Threadjoindemo
{
public static void main(String[] args)
{
// main thread calling join() on itself
Thread.currentThread().join(); // Program gets stuck, Deadlock suitation
}
}
5.总结
在本教程中,我们已经了解了加入两个线程的必要性以及如何使用 Thread.join() API,无论是否有过期时间。我们还看到了如何中断一个连接的线程。我们还学习了如何处理死锁情况,同时使用*join()*.
学习愉快!!
这个帖子对你有帮助吗?
如果你喜欢这篇文章,请告诉我们。这是我们能够改进的唯一方法。
有
没有