【问题标题】:Do I need to call join() when stopping a Thread in Java?在 Java 中停止线程时是否需要调用 join()?
【发布时间】:2018-06-24 21:20:42
【问题描述】:

我有这 5 个运行 while 循环的简单线程:

flasherThread = new Thread(new Runnable() {
    @Override
    public void run() {
        while(running.get()) {
            // do network stuff         
        }
    }
});

running 被声明为private final AtomicBoolean running;

我有这个方法:

public void stopFlasherThread() {
    running.set(false);
}

我的问题是将标志设置为 false 立即停止线程?还是我需要调用flasherThread.join() 来确保线程已经停止?

主要问题是我一次有 4-5 个。

所以我有一个循环,例如:

for (int i = 0; i < 5; i++) {
    ThreadArrayList.get(i).stopFlasherThread();
    ThreadArrayList.get(i).join()  // should I do this ?
}

任何帮助都会很棒!谢谢

【问题讨论】:

  • Thread#join 只是等到指定的线程死亡。如果这是您打算发生的事情,那么您应该调用它。
  • 退出 run 方法会停止线程。期间。
  • 你真的不需要创建自己的中断系统,它already exists
  • @D.B 并使用中断?
  • 如果你想保存线程管理,你可以使用 Fork-Join-Pool。您向这个池发送 RecursiveActions 或 RecursiveTasks,它们在不同的线程上进行处理。 Actions/Tasks 不一定是递归的,但如果您创建子问题并将其提交到池中,则可以是递归的。在这里您可以找到一个很长的解释:baeldung.com/java-fork-join,这里是一个斐波那契示例:dzone.com/articles/a-look-at-forkjoinpool

标签: java concurrency


【解决方案1】:

根据official documentation on join

join 方法允许一个线程等待另一个线程完成。如果 t 是其线程当前正在执行的 Thread 对象,

t.join();

导致当前线程暂停执行,直到t的线程终止。

所以,不...或者不一定,只有当您需要该线程的工作结果来做某事时。 join 不会停止/中断线程,它会等待它完成工作。 stopFlasherThread 将使循环停止。

我建议您使用 ExecutorService 在 Java 上使用不同的方法来使用线程。例如:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<AtomicInteger> futureResult = executor.submit(new Callable<AtomicInteger>() {
    @Override
    public AtomicInteger call() {
        // Here I return a random integer, but you can do your proper calculation
        AtomicInteger atomicInteger = 
            new AtomicInteger(ThreadLocalRandom.current().nextInt());
        System.out.println(Thread.currentThread().getName() + " " + atomicInteger);
        return atomicInteger;
    }
});

// Thread returns result, but continues to execute as it is a single thread pool
try {
    System.out.println(Thread.currentThread().getName() + " " + futureResult.get());
} catch (InterruptedException e) {
    // Handle exception properly
    e.printStackTrace();
} catch (ExecutionException e) {
    // Handle exception properly
    e.printStackTrace();
}

// Stop all threads
executor.shutdownNow();

在那里我定义了一个内联类,它扩展了Callable 接口并实现了call 方法以在另一个线程中执行任务。这将返回变量futureResult 中的计算结果,该变量是Future。由于 executor 是一个线程池,即使我们这里的任务已经解决,它仍然可以继续执行任务。要完成整个线程池循环,您可以执行executor.shutdownNow()

【讨论】:

  • 对于大多数常见的情况,当你有很多线程时,它会提供更简洁的代码,并让你的代码不那么复杂。这是stackoverflow.com/q/1094867/3294286 的一些辩论,但总体上首选执行者。我在生产系统中使用它们来处理对后端/外部系统的多个请求并且运行良好。
  • 如果我在不返回任何内容的真正循环中运行,这仍然可以吗?因为我读到了未来的任务..
  • 如果你使用 Future 和 Callable,你就不需要这些循环了。他们做异步工作并且不关心结果,或者您可以向期货添加超时(对于连接其他服务/应用程序非常有用),或者您可以等待执行以 invokeAll 结束。在这里,我找到了一个不错的教程,您可能会看:callicoder.com/java-callable-and-future-tutorial 将其与 ExecutorService 结合使用可为您提供非常强大的工具,可以使用繁重的多线程创建干净的后端服务器。
  • 我不太明白。 Callable 和 Future 关心结果,这就是它们返回值的重点......这将如何帮助我摆脱循环?
  • future.get() 将在可用时返回结果。并且 executorService.invokeAll() 将等待线程池中所有可调用对象的 future.get() 结果。如果您的任何可调用对象因异常而失败。如果您正在查看,则 invokeAll 方法将被阻塞。
猜你喜欢
  • 1970-01-01
  • 2012-08-02
  • 1970-01-01
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 2017-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多