使用 ExecutorService 时正在执行的附加任务是什么?

What is the additional task that is being executed when using ExecutorService?

我正在学习 Java 并发。所以在网上看到了这个例子。我写了下面的代码。问题是,即使任务已经执行完毕,看起来还有一些额外的东西正在执行。那么我如何找出正在执行的内容呢?

package com.test.executors;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.Logger;

class MyObject {
    private Integer number;
    private Integer result;

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public Integer getResult() {
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }
}

class FactorialCalculator implements Callable<MyObject> {

    private Integer number;

    public FactorialCalculator(Integer number) {
        this.number = number;
    }

    @Override
    public MyObject call() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " started...");
        MyObject object = new MyObject();
        object.setNumber(number);
        int result = 1;
        if (0 == number || 1 == number) {
            result = 1;
        } else {
            for (int i = 2; i <= number; i++) {
                result *= i;
                TimeUnit.SECONDS.sleep(1);
            }
        }
        object.setResult(result);
        System.out.println(Thread.currentThread().getName() + " done...");
        return object;
    }
}

public class ExecutorMain1 {

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(3);
        List<Future<MyObject>> results = new ArrayList<>();
        Random random = new Random();
        System.out.println("Starting Services...");
        for (int i = 0; i < 5; i++) {
            Integer number = random.nextInt(10);
            Future<MyObject> result = service.submit(new FactorialCalculator(number));
            results.add(result);
        }

        System.out.println("Done submitting tasks...");
        System.out.println("Will display results shortly...");

        for (Future<MyObject> future : results) {

            try {
                System.out.println("Number: " + future.get().getNumber() + "--> Result: " + future.get().getResult() + " Task Status: " + future.isDone());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Exiting main...");
    }
}

输出为-

Starting Services...
Done submitting tasks...
Will display results shortly...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-1 started...
pool-1-thread-1 done...
Number: 6--> Result: 720 Task Status: true
Number: 5--> Result: 120 Task Status: true
pool-1-thread-3 started...
pool-1-thread-3 done...
Number: 4--> Result: 24 Task Status: true
Number: 0--> Result: 1 Task Status: true
Number: 1--> Result: 1 Task Status: true
Exiting main...

Exiting main...之后,程序还没有退出。它正在阻止某些东西。提交的 5 个任务也已完成。那么正在执行什么?我如何找到它?

您需要显式调用 shutdown 来终止池中的线程。之后,jvm 可以关闭。

service.shutdown();
System.out.println("Exiting main...");

存在非守护线程时 JVM 不会退出 运行。 而您的 ExecutorService 创建了非守护进程工作线程。因此,要允许 JVM 终止,您需要关闭执行程序服务。通过调用 shutdown()shutdownNow() 因为你所有的任务都已经完成了。

对您的 "found code:" InterruptedException 的一个小评论几乎完全可以用作请求线程退出。将其视为正常异常通常是错误的。这行代码:

} catch (InterruptedException e) {
    e.printStackTrace();
}

可能没有用,没有理由仅仅因为您被要求退出就打印堆栈跟踪。

此外,当您捕获到 InterruptedException 并且您没有抛出它时,您必须为您的线程重置中断标志。

} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

这是因为代码的其他部分必须知道它们处于中断状态并且必须尽快退出。

C.f。 Brian Goetz 的 Java 并发实践