我使用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()方法? 谢谢你的帮助。
答案 0 :(得分:2)
有很多方法可以做到这一点。
<强> 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和期货(这真的像再次加入所有线程,所以你可能想跳过这个):
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
,这使我们可以将运行任务用作构建块。我们可以简单地构建一个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
的简单性,但是为您管理了线程。
答案 1 :(得分:1)
使用ExecutorService和线程池。别忘了把它关掉。请参阅此处的示例 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html。
E.g。
public class MyRunnable implements Runnable{
String name = "DefaultName";
public MyRunnable(String name){
this.name = name;
}
@Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.println(String.valueOf(i) + "# My Name: " + name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new MyRunnable("John"));
pool.execute(new MyRunnable("Jimm"));
pool.execute(new MyRunnable("Billy"));
pool.shutdown();
}
}
完成所有yor线程后,主方法就完成了,执行完毕。