Java 如何在ThreadPoolExecutor中管理池线程终止?

Java 如何在ThreadPoolExecutor中管理池线程终止?,java,multithreading,concurrency,exception-handling,Java,Multithreading,Concurrency,Exception Handling,引用实践中的并发: 要为池线程设置UncaughtExceptionHandler,请提供 ThreadFactory到ThreadPoolExecutor构造函数。(与所有人一样 线程操作,只有线程的所有者应该更改其 UncaughtExceptionHandler。)标准线程池允许未捕获 任务异常终止池线程,但使用try finally 发生这种情况时,将通知块,以便更换线程。 没有未捕获的异常处理程序或其他故障通知 在这种机制下,任务可能会出现无声的失败,这可能是非常困难的 令人困惑如果您

引用实践中的并发:

要为池线程设置UncaughtExceptionHandler,请提供 ThreadFactory到ThreadPoolExecutor构造函数。(与所有人一样 线程操作,只有线程的所有者应该更改其 UncaughtExceptionHandler。)标准线程池允许未捕获 任务异常终止池线程,但使用try finally 发生这种情况时,将通知块,以便更换线程。 没有未捕获的异常处理程序或其他故障通知 在这种机制下,任务可能会出现无声的失败,这可能是非常困难的 令人困惑如果您希望在任务因错误而失败时收到通知 异常,以便您可以执行某些特定于任务的恢复操作, 使用捕获任务的Runnable或Callable包装任务 异常或重写THReadPoolExecutor中的afterExecute挂钩

这本书没有提供如何实现这一点的任何例子

你能展示一下这个技巧吗

附笔。 我尝试编写代码示例:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread();
            thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    e.printStackTrace();
                }
            });
            System.out.println("created thread with id " + Thread.currentThread().getId());
            return thread;
        }
    });
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getId() + " started");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getId() + " termination");
            throw new RuntimeException();

        }
    };
    threadPoolExecutor.submit(runnable);
    threadPoolExecutor.submit(runnable);
    threadPoolExecutor.submit(runnable);
    threadPoolExecutor.submit(runnable);
}

始终。

您的代码中有几个错误。首先,必须将传递给
ThreadFactory
Runnable
传递给已创建的线程,否则,将导致断开的线程不执行任何任务。其次,您正在工厂中打印
Thread.currentThread()
的id,这显然不是新创建的线程。这就是为什么它会打印两次
1
的id

不过,在修复这些错误之后,您将不会看到未捕获的异常。原因是,虽然线程池执行器的行为如所述,但是
submit
方法将
Runnable
包装到一个
FutureTask
中,该任务本身捕获所有异常,以便在调用
get()
时可以报告这些异常

此时,我们必须记住,存在一个任意
可运行的
s队列,这些队列不一定是
FutureTask
实例。因此,未捕获的异常仍然是可能的,例如,当我们通过
execute
直接将可运行程序排队时

因此,固定示例:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1,
                TimeUnit.MINUTES, new LinkedBlockingQueue<>(), r -> {
                    Thread thread = new Thread(r);
                    thread.setUncaughtExceptionHandler((t, e) -> {
                        synchronized(System.out) {
                            System.out.println("Uncaught exception in "+t.getId());
                            e.printStackTrace(System.out);
                        }
                    });
                    System.out.println("created thread with id " + thread.getId());
                    return thread;
        });
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getId() + " started");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getId() + " termination");
            throw new RuntimeException();
            };
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.shutdown();
    }
}
当然,消息的数量和顺序可能不同

如引用中所述,您还可以通过重写执行后的
来了解异常:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1,
    TimeUnit.MINUTES, new LinkedBlockingQueue<>()) {
        @Override protected void afterExecute(Runnable r, Throwable t) {
            if(t!=null) synchronized(System.out) {
               System.out.println("Uncaught exception in "+Thread.currentThread().getId());
               t.printStackTrace(System.out);
            }
        }
    };
ThreadPoolExecutor ThreadPoolExecutor=新的ThreadPoolExecutor(2,4,1,
TimeUnit.MINUTES,新的LinkedBlockingQueue()){
@执行后覆盖受保护的void(可运行r、可丢弃t){
如果(t!=null)已同步(System.out){
System.out.println(“在”+Thread.currentThread().getId()中出现未捕获异常”);
t、 printStackTrace(系统输出);
}
}
};

尽管如此,在我的测试中,默认的未捕获异常处理程序也打印了堆栈跟踪…

您能否更清楚一点:如何实现什么?线程池已经做到了这一点(例如,它使用try/catch来知道发生了未捕获的异常,但否则会让异常冒泡,最终杀死其原始池线程)。似乎什么也做不到…@GPI如果我在ThreadFactory中使用ExceptionHandler,我会有什么收获?
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1,
    TimeUnit.MINUTES, new LinkedBlockingQueue<>()) {
        @Override protected void afterExecute(Runnable r, Throwable t) {
            if(t!=null) synchronized(System.out) {
               System.out.println("Uncaught exception in "+Thread.currentThread().getId());
               t.printStackTrace(System.out);
            }
        }
    };