166

在这段代码中,这两个 join 和 break 是什么意思?t1.join()导致t2停止直到t1终止?

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread t2 = new Thread(new EventThread("e2"));
t2.start();
while (true) {
   try {
      t1.join();
      t2.join();
      break;
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}
4

11 回答 11

335

这个线程连接代码是什么意思?

引用Thread.join()javadocs 方法

join()等待这个线程死掉。

有一个线程正在运行您的示例代码,它可能是主线程

  1. 主线程创建并启动t1t2线程。两个线程开始并行运行。
  2. 主线程调用t1.join()以等待t1线程完成。
  3. t1线程完成,方法t1.join()在主线程中返回。请注意,t1在调用之前可能已经完成,join()在这种情况下join()调用将立即返回。
  4. 主线程调用t2.join()以等待t2线程完成。
  5. t2线程完成(或者它可能在线程完成之前完成)t1并且t2.join()方法在主线程中返回。

重要的是要了解t1t2线程一直在并行运行,但是启动它们的主线程需要等待它们完成才能继续。这是一种常见的模式。此外,t1和/或t2可能在主线程调用它们之前join()完成。如果是这样,则join()不会等待,而是会立即返回。

t1.join()意味着导致 t2 停止直到 t1 终止?

不会。正在调用的t1.join()线程将停止运行并等待t1线程完成。线程并行运行,t2完全不受调用影响t1t1.join()

就 try/catch 而言,join()throwsInterruptedException意味着正在调用的主线程join()本身可能被另一个线程中断。

while (true) {

while循环中加入连接是一种奇怪的模式。通常,您会进行第一次连接,然后InterruptedException在每种情况下进行适当处理的第二次连接。无需将它们置于循环中。

于 2013-04-11T18:35:21.043 回答
75

这是一个最受欢迎的 Java 面试问题。

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread e2 = new Thread(new EventThread("e2"));
t2.start();

while (true) {
    try {
        t1.join(); // 1
        t2.join(); // 2  These lines (1,2) are in in public static void main
        break;
    }
}

t1.join()意思是,t1 说“我想先完成”。情况也是如此t2。无论是谁启动t1t2线程(在本例中为main方法),main 都会等到t1t2完成他们的任务。

但是,需要注意的重要一点是,t1它们t2本身可以并行运行,而与 和 上的加入调用t1顺序 无关t2。它是必须等待main/daemon的线程。

于 2013-04-11T18:38:35.087 回答
52

join()表示等待线程完成。这是一种拦截方法。join()您的主线程t1.join()t1执行t2.join().

于 2013-04-11T18:37:18.037 回答
42

一张图片胜过千言万语。

    Main thread-->----->--->-->--block##########continue--->---->
                 \                 |               |
sub thread start()\                | join()        |
                   \               |               |
                    ---sub thread----->--->--->--finish    

希望有用,更多详情请点击这里

于 2017-11-24T07:25:39.973 回答
12

当线程 tA 调用 tB.join() 时,其原因不仅是等待 tB 死亡或 tA 自身被中断,而且会在 tB 中的最后一条语句和 tA 线程中 tB.join() 之后的下一条语句之间创建发生前的关系。

线程中的所有操作都发生在任何其他线程从该线程上的 join() 成功返回之前。

是程序的意思

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        threadB.join();

        while (true) 
            System.out.print(sharedVar);
    }
}

始终打印

>> 1111111111111111111111111 ...

但是程序

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        // threadB.join();  COMMENT JOIN

        while (true)
            System.out.print(sharedVar);
    }
}

不仅可以打印

>> 0000000000 ... 000000111111111111111111111111 ...

>> 00000000000000000000000000000000000000000000 ... 

始终只有“0”。

因为Java内存模型不需要在没有heppens-before关系的情况下将'sharedVar'的新值从threadB'传输'到主线程(线程启动,线程连接,'synchonized'关键字的使用,AtomicXXX变量的使用等)。

于 2016-07-13T14:51:32.850 回答
6

简单地说:完成
t1.join()后返回t1。除了等待它完成之外,
它不会对 thread 做任何事情。 自然,后面的代码 只会在 返回后执行。t1
t1.join()t1.join()

于 2018-04-27T18:26:14.653 回答
3

来自关于 Joins 的 oracle 文档页面

join方法允许一个线程等待另一个线程完成。

如果 t1 是Thread其线程当前正在执行的对象,

t1.join() : causes the current thread to pause execution until t1's thread terminates.

如果 t2 是Thread其线程当前正在执行的对象,

t2.join(); causes the current thread to pause execution until t2's thread terminates.

joinAPI是低级API,在java早期版本中已经引入。在一段时间内(尤其是 jdk 1.5 版本),在并发方面发生了很多变化。

您可以使用 java.util.concurrent API 实现相同的目的。一些例子是

  1. 使用invokeAll _ExecutorService
  2. 使用CountDownLatch
  3. 使用ForkJoinPoolnewWorkStealingPoolExecutors从 java 8 开始)

参考相关的SE问题:

等到所有线程在java中完成它们的工作

于 2016-04-19T19:06:33.823 回答
3

对我来说,Join() 行为总是令人困惑,因为我试图记住谁会等待谁。不要试图那样记住它。

下面是纯 wait() 和 notify() 机制。

我们都知道,当我们在任何 object(t1) 上调用 wait() 时,调用 object(main) 会被发送到等候室(阻塞状态)。

在这里,主线程正在调用 join(),这实际上是 wait()。所以主线程会一直等到收到通知。t1 完成运行(线程完成)时会发出通知。

收到通知后,main 走出等候室,继续执行。

于 2019-03-23T21:27:53.143 回答
0

希望能帮助到你!

package join;

public class ThreadJoinApp {

    Thread th = new Thread("Thread 1") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());

            //Thread 2 waits until the thread 1 successfully completes.
            try {
            th.join();
            } catch( InterruptedException ex) {
                System.out.println("Exception has been caught");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    public static void main(String[] args) {
        ThreadJoinApp threadJoinApp = new ThreadJoinApp();
        threadJoinApp.th.start();
        threadJoinApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}
于 2019-07-14T12:01:45.463 回答
0

join() 方法用于保持当前正在运行的线程的执行,直到指定的线程死亡(完成执行)。

为什么我们使用 join() 方法?

一般情况下我们一般有多个线程,线程调度器调度线程,不保证线程的执行顺序。

我们来看一个例子,新建项目,复制如下代码:

这是 activity_main.xml 代码:

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btn_without_join"
    app:layout_constraintTop_toTopOf="parent"
    android:text="Start Threads Without Join"/>
 <Button
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:id="@+id/btn_with_join"
     app:layout_constraintTop_toBottomOf="@id/btn_without_join"
     android:text="Start Threads With Join"/>
 <TextView
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:id="@+id/tv"
     app:layout_constraintTop_toBottomOf="@id/btn_with_join"
     />

 </androidx.constraintlayout.widget.ConstraintLayout>

这是 MainActivity.java 的代码:

public class MainActivity extends AppCompatActivity {

TextView tv;
volatile  String threadName = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv = findViewById(R.id.tv);
    Button btn_without_join = findViewById(R.id.btn_without_join);
    btn_without_join.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            withoutJoin();
        }
    });
    Button btn_with_join = findViewById(R.id.btn_with_join);
    btn_with_join.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            withJoin();
        }
    });
}
private void withoutJoin()
{
    tv.setText("");
    Thread th1 = new Thread(new MyClass2(), "th1");
    Thread th2 = new Thread(new MyClass2(), "th2");
    Thread th3 = new Thread(new MyClass2(), "th3");
    th1.start();
    th2.start();
    th3.start();
}
private void withJoin()
{
    tv.setText("");
    Thread th1 = new Thread(new MyClass2(), "th1");
    Thread th2 = new Thread(new MyClass2(), "th2");
    Thread th3 = new Thread(new MyClass2(), "th3");
    th1.start();
    try {
        th1.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    th2.start();
    try {
        th2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    th3.start();
}
class MyClass2 implements Runnable{

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        runOnUiThread(new Runnable() {
            public void run() {
                tv.setText(tv.getText().toString()+"\n"+"Thread started: "+t.getName());
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
        runOnUiThread(new Runnable() {
            public void run() {
                tv.setText(tv.getText().toString()+"\n"+"Thread ended: "+t.getName());
            }
        });

    }
}
}

如果您按下第一个按钮(Start Threads without Join),这将是结果: 在此处输入图像描述

如果您按下第二个按钮(Start Threads With Join),这将是结果: 在此处输入图像描述

于 2022-02-14T08:51:26.660 回答
-3

假设我们的主线程启动线程 t1 和 t2。现在,当调用 t1.join() 时,主线程会挂起自己,直到线程 t1 死亡然后恢复自己。类似地,当 t2.join() 执行时,主线程再次挂起自己,直到线程 t2 死亡然后恢复。

所以,这就是它的工作原理。

此外,这里并不真正需要 while 循环。

于 2018-04-05T07:13:33.023 回答