【问题标题】:Can this thread be alive and how to use java.lang.Thread.join() method这个线程是否可以存活以及如何使用 java.lang.Thread.join() 方法
【发布时间】:2015-04-21 13:49:23
【问题描述】:

我之前读过一些 SO 问题和文档,但没有找到我的回复:

所以...

public class MyThread extends Thread {
  public MyThread() {
    this.setName("MyThread-" + System.currentTimeMillis());
    this.start();
  }

  public MyThread(long millis) throws InterruptedException {
    this.setName("MyThread-" + System.currentTimeMillis());
    this.join(millis);
    this.start();
  }

  @Override
  public void run() {
    System.out.println("I am running...");
    // This thread does not sleep... no Thread.sleep() in run method.
    // Do some things like requesting a database
    // Database response happens in less time that the timeout
  }
}

public class MyClass {

  public MyClass(){
    for (int i = 0; i < 5; i++) {
      Thread t1 = new MyThread();
      t1.join(5000);
      if (t1.isAlive()) {
        System.out.println("I'm alive");
        // do some things
      } else {
        System.out.println("I'm not alive");
      }

      Thread t2 = new MyThread(5000);
      if (t2.isAlive()) {
        System.out.println("I'm alive");
        // do some things
      } else {
        System.out.println("I'm not alive");
      }

    }
  }
}

似乎不可能,但t1 之一可能还活着吗? t2 呢? 当我在start() 之后调用join() 时发生了什么

有关信息,我正在使用:

  • JVM:Java HotSpot(TM) 客户端 VM(20.45-b01,混合模式,共享)
  • Java:版本 1.6.0_45,供应商 Sun Microsystems Inc.

阅读您的部分回复后更新

如果我理解,更好的实现应该是这样的:

public class MyThread extends Thread {
  public MyThread() {
    super("MyThread-" + System.currentTimeMillis());
  }

  @Override
  public void run() {
    System.out.println("I am running...");
    // This thread does not sleep... no Thread.sleep() in run method.
    // Do some things like requesting a database
    // Database response happens in less time that the timeout
  }
}

public class MyClass {

  public MyClass(){
    for (int i = 0; i < 5; i++) {
      Thread t1 = new MyThread();
      t1.start();
      t1.join(5000);

      if (t1.isAlive()) {
        System.out.println("I'm alive");
        // do some things
      } else {
        System.out.println("I'm not alive");
      }
    }
  }
}

两个回复都对我有很大帮助:https://stackoverflow.com/a/29775219/1312547https://stackoverflow.com/a/29775083/1312547

【问题讨论】:

  • 两个注释,虽然它们没有回答你的问题:首先,你为什么在构造函数中开始之前加入线程?其次,您实际上不应该从其构造函数中启动线程。原因有点微妙,但如果你这样做,基本上一堆方便推理的线程保证就会消失。您应该始终先构建它,然后再启动它。
  • It is recommended to implement Runnable instead of extend Thread。我建议您首先在代码中遵循多线程的良好实践,然后重写您的测试。
  • 同上 yshavit 所说的:从构造函数中调用 this.start() 是一个坏主意。它可能允许新线程的 run() 方法看到处于未初始化状态的 Thread 对象。将 start() 调用移动到 MyClass() 构造函数中。并在调用 .start() 之前调用 .join()?你读过文档吗?
  • @jameslarge 没有提到他甚至没有打电话给super()
  • 通过您的修改,您现在的问题究竟是什么?你到底想达到什么目的?

标签: java multithreading jdk1.6


【解决方案1】:

isAlive() 的文档说:

如果线程已启动且尚未死亡,则线程处于活动状态。

join() 的文档说:

最多等待几毫秒让该线程终止

所以,在join()返回后,

  • 线程已经死亡,isAlive() 为假
  • 或线程尚未终止但延迟已过,isAlive() 可能为真。这是可能的,但极不可能,因为线程有 5 秒的时间来完成打印到控制台的简单工作。

【讨论】:

    【解决方案2】:

    请注意,虽然 Thread.join(long) 的 (JDK 7) 文档说

    最多等待millis 毫秒让该线程终止。

    它也继续

    此实现使用以this.isAlive 为条件的this.wait 调用循环。

    Thread.isAlive 说:

    如果线程已启动且尚未死亡,则线程处于活动状态。

    所以你的代码:

    • 调用t1.isAlive() 时,始终为false,因为您是在启动线程(从构造函数)后加入的。
    • 调用t2.isAlive()时,大部分时间是true,因为
      • 您在启动线程之前加入(在构造函数中),立即返回
      • 线程刚刚启动(在构造函数中)

    所以回答你的问题

    似乎不可能,但t1 之一可能还活着吗?

    对于t1,只要您等待的时间超过它运行所需的时间。对于t2

    【讨论】:

    • 'this.wait 调用的循环以 this.alive 为条件'是否意味着如果isAlive()==false 然后线程重新回到类似状态,直到在我的情况下等待 5 秒?这适用于 Java v1.6 吗?
    • 我不确定是否理解您的评论,但如果!isAlive(),那么join(…) 会立即返回,无需等待。 Java 6 中的行为相同,但 Java 7 中的文档已更新以反映此行为(在 isAlive() 上循环)。
    【解决方案3】:

    你的t1.isAlive() 永远是假的。您正在执行的线程需要一毫秒才能运行。您正在调用t1.join(5000),它将该线程与当前线程一旦死亡连接起来。因为它的运行速度总是快于 5 秒,所以当它到达你是否还活着的检查时它总是死的。

    您的t2.isAlive() 将永远是真实的。在 t2 线程上,您在调用 start 方法之前在构造函数中调用 join。由于在调用 start 方法之前线程总是死的,因此构造函数中的 join 立即返回。然后允许调用 start 。即使在线程上调用 start 也不意味着它会立即执行。它只是将其标记为可以执行,线程调度程序将在将来的某个时间启动它。由于您在构造函数之后立即调用t2.isAlive(),因此它将始终为真,因为当前线程还不会被换出。

    【讨论】:

      【解决方案4】:

      使用您的代码,t1 线程肯定会始终打印“我还活着”,t2,“我还活着”。

      对于t2 线程,在启动线程之前调用this.join(...) 很奇怪,因为(作为@JB 指出的补充),join() doc

      此实现使用一个循环 this.wait 调用以 this.isAlive 为条件。

      而且,由于线程还没有启动,所以join没有作用,立即返回。

      但是你的问题是什么可以让t1 活着。只需在run() 方法中添加Thread.sleep(6000),您就会看到线程是活动的。意思是如果线程完成的任务(DB请求,...)比join()中设置的超时时间长,那么答案是“是的,t1可以活着”。

      【讨论】:

      • 您是否建议:构造线程(Thread t = new Thread();),然后启动它(t.start();),最后调用join(t.join(5000);)?按这个顺序?或者更好的是t.join(5000);t.start();
      • 我不知道你想做什么,但正如所说,在构造函数中调用this.join(5000); this.start(); 时,join() 不会做任何事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      • 2019-10-25
      • 1970-01-01
      • 1970-01-01
      • 2023-01-05
      • 2018-03-06
      相关资源
      最近更新 更多