当一个线程在线程池中执行时抛出异常会发生什么?
它会终止并成为垃圾回收吗?
背景:
我正在使用ScheduledThreadPoolExecutor
来定期运行任务,并且Netty也在使用它。现在,使用此应用程序的客户端告诉我,他们有时会注意到一堆客户端被随机断开连接,每次这种情况发生时,都会记录下一个与Netty无关的任务的堆栈跟踪。我的假设是线程被中断并垃圾回收,因此Netty失去了对线程的任何引用并断开了分配的TCP客户端的连接。
当一个线程在线程池中执行时抛出异常会发生什么?
它会终止并成为垃圾回收吗?
背景:
我正在使用ScheduledThreadPoolExecutor
来定期运行任务,并且Netty也在使用它。现在,使用此应用程序的客户端告诉我,他们有时会注意到一堆客户端被随机断开连接,每次这种情况发生时,都会记录下一个与Netty无关的任务的堆栈跟踪。我的假设是线程被中断并垃圾回收,因此Netty失去了对线程的任何引用并断开了分配的TCP客户端的连接。
threadPool.execute(...)
还是threadPool.submit(...)
。如果使用execute(...)
且任务抛出未捕获的异常,则线程终止,线程池忘记该线程并立即启动另一个线程(如果适用)。任务和线程可以被垃圾回收。如果使用submit(...)
,则任务将完成,异常将被捕获,线程将继续运行,并出队下一个提交到线程池的作业并执行它。您可以通过扩展ThreadPoolExecutor
并覆盖以下内容来查看抛出的异常:protected void afterExecute(Runnable r, Throwable t) { }
submit(...)
时,线程池会捕获任务抛出的所有异常,因此可以使用Future
报告任务的状态。如果使用execute(...)
,则线程将终止并且它和任务可以被垃圾回收。如果使用submit(...)
,则线程不会终止,但是任务可以被垃圾回收。现在有不同的方式来减少运行中的线程数,这可能会导致线程终止并且可以被垃圾回收。RuntimeException
或其他异常。如果发生这种情况,线程池会在任务完成后清除中断,并从队列中取下一个任务。public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(1);
// this thread will be killed and replaced
threadPool.execute(new Task());
// this thread will catch and handle the exception and run the following task
threadPool.submit(new Task());
threadPool.submit(new Task());
}
private static class Task implements Runnable {
@Override
public void run() {
// this should print out the same thread ids even though the task threw
System.out.println(Thread.currentThread().getId());
throw new RuntimeException();
}
}
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadExample1 {
private volatile ThreadPoolExecutor threadPoolExecutor;
public static void main(String[] args) throws InterruptedException {
ThreadExample1 threadExample1 = new ThreadExample1();
threadExample1.doTheWork();
}
private void doTheWork() throws InterruptedException {
Scanner scanner = new Scanner(System.in);
ThreadFactory myThreadFactory = new MyThreadFactory("task");
threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2, myThreadFactory);
System.out.println("before task is sent to be executed: thread pool size: " + threadPoolExecutor.getPoolSize() + ", core pool size: " + threadPoolExecutor.getCorePoolSize() + " - threads active count: " + threadPoolExecutor.getActiveCount());
scanner.next();
threadPoolExecutor.execute(new MyTask());
System.out.println("immediately after task is sent to be executed: thread pool size: " + threadPoolExecutor.getPoolSize() + ", core pool size: " + threadPoolExecutor.getCorePoolSize() + " - threads active count: " + threadPoolExecutor.getActiveCount());
scanner.next();
System.out.println("going to sleep");
Thread.sleep(2000);
System.out.println("going to sleep");
System.out.println("after waking up");
System.out.println("after waking up: thread pool size: " + threadPoolExecutor.getPoolSize() + ", core pool size: " + threadPoolExecutor.getCorePoolSize() + " - threads active count: " + threadPoolExecutor.getActiveCount());
scanner.next();
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS);
}
class MyThreadFactory implements ThreadFactory {
Logger logger = Logger.getLogger("MyThreadFactory");
private int counter = 0;
private String prefix = "";
public MyThreadFactory(String prefix) {
this.prefix = prefix;
}
@Override
public Thread newThread(Runnable r) {
counter++;
String name = prefix + "-" + counter;
logger.log(Level.WARNING, "thread: " + name + " - is going to be created");
System.out.println("before a new thread is created. pool size: " + threadPoolExecutor.getPoolSize() + ", core pool size: " + threadPoolExecutor.getCorePoolSize() + " - threads active count: " + threadPoolExecutor.getActiveCount());
return new Thread(r, name);
}
}
}
class MyTask implements Runnable {
Logger logger = Logger.getLogger("MyTask");
@Override
public void run() {
while (true) {
System.out.println("thread: " + Thread.currentThread().getName() + " - current state: " + Thread.currentThread().getState());
throw new RuntimeException("something bad happened");
}
}
}