gpt4 book ai didi

java - 线程完成后触发 System.exit()

转载 作者:行者123 更新时间:2023-12-01 20:15:55 25 4
gpt4 key购买 nike

我从一个具有 main 方法的类启动多个线程,

public static void main(String[] args) {
for (int i = 0; i <= ALimit - 1; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
Thread myThread= new Thread(myThreadImplementsRunnable);
myThread.start();
}
}

线程完成工作后,主线程仍在运行。如果我在 for 循环之后调用 System.exit(0),我的线程将无法完成其执行,事实上,它们甚至不会启动。有没有办法在所有线程完成执行后触发 System.exit(0),而不在每个线程上调用 join() 方法?感谢您的帮助。

最佳答案

有多种方法可以做到这一点。

<强>1。加入所有生成的线程。 (哦,对了,你不想要这个,跳到2)

这意味着保留对所有这些线程的引用:

public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[ALimit]; // array to keep track of our threads, or we could use a Collection
for (int i = 0; i < ALimit; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
Thread myThread= new Thread(myThreadImplementsRunnable);
threads[i] = myThread; // remember it
myThread.start();
}
for (Thread thread : threads) {
thread.join(); // wait until the thread finishes, will return immediately if it's already finished.
}
System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

<强>2。使用 CountDownLatch :

CountDownLatch 基本上是一个倒计时,线程可以等待倒计时达到 0。因此,如果每个完成倒计时的线程,主线程可以等待 0;

public static void main(String[] args) throws InterruptedException {
CountDownLatch finishedRunning = new CountDownLatch(ALimit); // Latch with ALimit countdowns needed to flip
for (int i = 0; i < ALimit; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
Thread myThread= new Thread(() -> {
try {
myThreadImplementsRunnable.run();
} finally {
finishedRunning.countDown(); // one less to wait for, in a finally block, so exceptions don't mess up our count
}
};
myThread.start();
}
finishedRunning.await(); // waits until the count is 0
System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

<强>3。使用 ExecutorService 并关闭:

ExecutorService 为您管理线程,您可以执行任务,然后只需等待 ExecutorService 终止即可;

public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(ALimit);
for (int i = 0; i < ALimit; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
executorService.execute(myThreadImplementsRunnable);
}
executorService.shutdown(); // will stop accepting new tasks, but all submitted tasks so far, will still be executed
boolean terminated = executorService.awaitTermination(3, TimeUnit.MINUTES); // we have to specify a timeout, returns a boolean which we can use to test whether it timed out or not, to maybe try and force termination
if (!terminated) {
// try and force things? Shut down anyway? log and wait some more?
}
System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

<强>4。使用 ExecutorService 和 futures(这实际上就像再次加入所有线程,所以你可能想跳过这个):

ExecutorService 为您管理线程,您可以提交任务,跟踪返回的 Future,然后只需等待每个 Future 的结果 到达;

public static void main(String[] args) throws InterruptedException {
Set<Future<?>> futures = new HashSet<>();
ExecutorService executorService = Executors.newFixedThreadPool(ALimit);
for (int i = 0; i < ALimit; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
Future<?> future = executorService.submit(myThreadImplementsRunnable);
futures.add(future); // remember the future, pun intended ;)
}
executorService.shutdown(); // make sure the services terminates its threads when they're no longer needed.
for (Future<?> future : futures) {
try {
future.get();
} catch (ExecutionException e) {
// task failed with an exception : e.getCause() to see which
}
}
System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

此方法的一种变体是将 ExecutorService 包装在 CompletionService 中,它将按完成的顺序返回 Future:

public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(ALimit);
CompletionService<Void> completionService = new ExecutorCompletionService<Void>(executorService);
for (int i = 0; i <= ALimit - 1; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
completionService.submit(myThreadImplementsRunnable, null);
}
executorService.shutdown(); // make sure the services terminates its threads when they're no longer needed.
for (int i = 0; i < ALimit; i++) {
Future<?> future = completionService.take();
try {
future.get();
} catch (ExecutionException e) {
// task failed with an exception : e.getCause() to see which
}
}
System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

<强>5。使用CompletableFutures

Java 8 为我们带来了 CompletableFuture,它允许我们使用正在运行的任务作为构建 block 。我们可以简单地构建一个 CompletableFuture 来表示我们所有的异步任务。

public static void main(String[] args) throws InterruptedException {

CompletableFuture<?>[] completableFutures = new CompletableFuture<?>[ALimit];
for (int i = 0; i <ALimit; i++) {
MyThreadImplementsRunnable myThreadImplementsRunnable= new MyThreadImplementsRunnable();
completableFutures[i] = CompletableFuture.runAsync(myThreadImplementsRunnable);
}
CompletableFuture<Void> all = CompletableFuture.allOf(completableFutures);

try {
all.get(); // get the 'combined' result
} catch (ExecutionException e) {
// task failed with an exception : e.getCause() to see which
}

System.exit(0); // all threads have finished, frankly it's a bit superfluous now.
}

结论

CountDownLatch 可能就是您想要的,它很简单,而且开销很小。

ExecutorService 是专业人士会使用的,它清楚地分离了线程和任务的概念,提供了使用 Future 的选项,您可以取消它,并且可以使用它为各个任务提供异常处理。线程可以重复使用,并且可以独立于任务数量来定制线程数量。但所有这些可能都太过分了。

CompletionService 非常适合您需要在任务完成后立即处理任务的情况。

CompletableFuture 提供了 CountDownLatch 的简单性,但线程是为您管理的。

关于java - 线程完成后触发 System.exit(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45821312/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com