有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java触发一个系统。线程完成后退出()

我用一个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();
    }
}

线程完成工作后,主线程仍在运行。如果我呼叫一个系统。退出(0)在for循环之后,我的线程将不会完成它们的执行,事实上,它们甚至不会启动。 有没有办法触发一个系统。在所有线程完成执行后退出(0),而不对每个线程调用join()方法? 谢谢你的帮助


共 (2) 个答案

  1. # 1 楼答案

    使用ExecutorService和线程池。别忘了把它关掉。请参见此处的示例 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

    例如

    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();
        }
    }
    

    一旦所有你的线程都完成了,你的主方法就完成了,执行也就完成了

  2. # 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基本上是一个倒计时,线程可以等待倒计时达到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终止

    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

    Java8为我们带来了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的简单性,但是线程是为您管理的