【问题标题】:What does this thread join code mean?这个线程连接代码是什么意思?
【发布时间】:2013-04-04 02:06:26
【问题描述】:

在这段代码中,两个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();
   }
}

【问题讨论】:

标签: java multithreading


【解决方案1】:

这个线程加入代码是什么意思?

引用Thread.join() method javadocs

join() 等待该线程终止。

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

  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()main 线程将停止运行并等待t1 线程完成。 t2 线程并行运行,完全不受t1t1.join() 调用的影响。

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

while (true) {

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

【讨论】:

  • +1 这是一个非常奇怪的模式,可能可以删除。
  • 如果 t1 先完成,然后 t2 完成。这似乎是一个连续的过程。一个线程首先完成,然后另一个。多线程有什么意义?
  • 因为t1t2 可以并行运行。只是main 需要它们都完成才能继续。这是@user697911 的典型模式。
  • while 循环存在是因为(我猜)它想在join() 调用被中断时重试?我当然不会那样写@user697911。
  • 循环用于确保t1t2 都完成。 IE。如果t1 抛出InterruptedException,它将循环返回并等待t2。另一种方法是在各自的 Try-Catch 中等待两个线程,这样可以避免循环。此外,根据EventThread,这样做是有意义的,因为我们正在运行 2 个线程,而不是一个。
【解决方案2】:

这是一个最喜欢的 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 完成他们的任务。

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

【讨论】:

  • 很好的例子。关于“可以并行运行”:那又怎样?重要的是主线程将首先等待 t1,然后等待 t2。 t1 或 t2 在做什么真的没关系(从主线程的角度来看)
  • 你提到了“主/守护进程”线程。我理解的主要内容,但守护进程与它无关。主线程是非守护线程。
  • t1.join(); t2.join(); 将不允许执行连接的线程继续,直到两个线程都终止。在其他地方没有非常不寻常的代码的情况下,连接的顺序无关紧要。
  • 那么 t2.join() 只有在 t1 完成后才会被调用吗?
  • 换句话说,如果我们想“序列化” t1 和 t2 线程的执行,我们需要将 t1.join() 放在 t1.start() 之后,因为主线程启动了 t1(和 t2之后),当然也可以从 try/catch 中删除它。显然,这样做的后果将是失去并行性。
【解决方案3】:

join() 表示等待线程完成。这是一种拦截方法。您的主线程(执行join() 的线程)将在t1.join() 行上等待,直到t1 完成其工作,然后将对t2.join() 执行相同的操作。

【讨论】:

    【解决方案4】:

    一张图片胜过一千个字。

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

    希望有用,更多详情点击here

    【讨论】:

    • 清晰准确。
    • 调用join()的线程是处于BLOCKED状态还是WAITING状态?
    • 当一个线程被阻塞等待一个监视器时,它的状态是BLOCKED。当一个线程正在等待另一个线程时,它的状态是WAITING。更多详情请点击我的其他博客。 java thread state
    • 没有回答问题。
    【解决方案5】:

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

    All actions in a thread happen-before any other thread successfully returns from a join() on that thread.

    意思是程序

    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 变量的使用等)。

    【讨论】:

      【解决方案6】:

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

      【讨论】:

      • 只有在t1.join()返回+1后才会执行
      【解决方案7】:

      来自 oracle 文档page on Joins

      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.
      

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

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

      1. ExecutorService 上使用invokeAll
      2. 使用CountDownLatch
      3. 使用ExecutorsForkJoinPoolnewWorkStealingPool(从java 8 开始)

      参考相关的 SE 问题:

      wait until all threads finish their work in java

      【讨论】:

        【解决方案8】:

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

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

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

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

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

        【讨论】:

        • 嗯,这是否意味着我可以将其视为 javascript 的 await 函数?哈哈
        【解决方案9】:

        希望对您有所帮助!

        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
        }
        

        【讨论】:

          【解决方案10】:

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

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

          另外,这里也不需要 while 循环。

          【讨论】:

            猜你喜欢
            • 2012-06-06
            • 2011-05-28
            • 2011-04-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多