代码栗子:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.Test;
import java.util.concurrent.*;
import java.util.stream.IntStream;
public class ThreadExecutor {
private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(200),
new ThreadFactoryBuilder()
.setNameFormat("customThread %d")
.setUncaughtExceptionHandler((t, e) -> System.out.println("UncaughtExceptionHandler捕获到:" + t.getName() + "发生异常" + e.getMessage())) //设置Thread类的uncaughtExceptionHandler属性
.build());
@Test
public void test() {
IntStream.rangeClosed(1, 5).forEach(i -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//threadPoolExecutor.excute
Future<?> future = threadPoolExecutor.submit(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "执行");
int j = 1 / 0;
});
try {
future.get();//gets时才会抛出异常
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
}
}
线程遇到未处理的异常就结束了
这个好理解,当线程出现未捕获异常的时候就执行不下去了,留给它的就是垃圾回收了。
线程池中线程频繁出现未捕获异常
当线程池中线程频繁出现未捕获的异常,那线程的复用率就大大降低了,需要不断地创建新线程。
当异常捕获了(try,catch),线程就可以复用了;
问题来了,我们的代码中异常不可能全部捕获
如果要捕获那些没被业务代码捕获的异常,可以`设置Thread类的uncaughtExceptionHandler属性`。这时使用ThreadFactoryBuilder会比较方便,ThreadFactoryBuilder是guava提供的ThreadFactory生成器。
线程池中原有的线程没有复用!
所以通过UncaughtExceptionHandler想将异常吞掉使线程复用这招貌似行不通。它只是做了一层异常的保底处理。
将excute改成submit即可
通过submit提交线程可以屏蔽线程中产生的异常,达到线程复用。当get()执行结果时异常才会抛出。
原因是通过submit提交的线程,当发生异常时,会将异常保存,待future.get();时才会抛出。