很容易理解,线程遇到未处理的异常就结束了。当一个线程遇到未捕获的异常,就无法继续执行,留给它的就是垃圾回收。线程池中的线程频繁出现未捕获的异常当线程池中的线程频繁出现未捕获的异常时,线程的复用率大大降低,需要不断地创建新的线程。做一个实验:publicclassThreadExecutor{privateThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(1,1,60,TimeUnit.SECONDS,newArrayBlockingQueue<>(200),newThreadFactoryBuilder().setNameFormat("customThread%d").build());@Testpublicvoidtest(){IntStream.rangeClosed(1,5).forEach(i->{try{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}threadPoolExecutor.execute(()->{intj=1/0;});});}}新建一个只有一个线程的线程池,每0.1s提交一个任务,任务为1/0计算。线程“customThread0”中的异常java.lang.ArithmeticException:/在thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)处为零java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)atjava.lang.Thread.run(Thread.java:748)Exceptioninthread"customThread1"java.lang.ArithmeticException:/byzeroatthread.ThreadExecutor.lambda$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)在java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617))在java.lang.Thread.run(Thread.java:748)Exceptioninthread"customThread2"java.lang.ArithmeticException:/byzeroatthread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)在java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)atjava.lang.Thread.run(Thread.java:748)Exceptioninthread"customThread3"java.lang.ArithmeticException:/byzeroatthread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)在java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)在java.lang.Thread.run(Thread.java:748)线程“customThread4”中的异常java.lang.ArithmeticException:/在thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor处为零。runWorker(ThreadPoolExecutor.java:1142)在java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)在java.lang.Thread.run(Thread.java:748)线程“customThread5”java.lang.ArithmeticException:/在thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)在java.util.concurrent.ThreadPoolExecutor.r处为零unWorker(ThreadPoolExecutor.java:1142)atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)atjava.lang.Thread.run(Thread.java:748)可以看出执行的线程每次都不一样,之前的线程之所以没有被重用,是因为一个未捕获的异常。让我们尝试捕获异常:publicclassThreadExecutor{privateThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(1,1,60,TimeUnit.SECONDS,newArrayBlockingQueue<>(200),newThreadFactoryBuilder().setNameFormat("customThread%d")。建造());@Testpublicvoidtest(){IntStream.范围关闭(1、5)。forEach(i->{try{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}threadPoolExecutor.execute(()->{try{intj=1/0;}catch(异常e){System.out.println(Thread.currentThread().getName()+""+e.getMessage());}});});}}customThread0/byzerocustomThread0/byzerocustomThread0/byzerocustomThread0/byzerocustomThread0/byzero可以看出,当异常被捕获时,线程可以被复用。问题是我们不可能捕获代码中的所有异常。如果要捕获那些业务代码没有捕获到的异常,可以设置Thread类的uncaughtExceptionHandler属性。这时候使用ThreadFactoryBuilder就比较方便了。ThreadFactoryBuilder是guava提供的ThreadFactory生成器。newThreadFactoryBuilder().setNameFormat("customThread%d").setUncaughtExceptionHandler((t,e)->System.out.println(t.getName()+"发生异常"+e.getCause())).build()修改后:publicclassThreadExecutor{privatestaticThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(1,1,60,TimeUnit.SECONDS,newArrayBlockingQueue<>(200),newThreadFactoryBuilder().setNameFormat("customThread%d").settionUncaughtExcepler((t,e)->System.out.println("UncaughtExceptionHandlercaught:"+t.getName()+"发生异常"+e.getMessage())).build());@Testpublicvoidtest(){IntStream.rangeClosed(1,5).forEach(i->{try{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}threadPoolExecutor.execute(()->{System.out.println("Thread"+Thread.currentThread().getName()+"Execution");intj=1/0;});});}}线程customThread0ExecutionUncaughtExceptionHandlercaught:customThread0occurredexception/byzerothreadcustomThread1执行UncaughtExceptionHandler捕获:customThread1异常发生/零线程customThread2执行UncaughtExceptionHandler捕获:customThread2执行异常/零线程customThread3执行UncaughtExceptionHandler捕获:customThread3执行异常/零线程customThread4执行UncaughtExceptionHandler捕获到:customThread4异常/by0可见,结果不是我们想象的,线程池中原来的线程没有被重用!所以使用UncaughtExceptionHandler来吞掉异常,让线程重用似乎行不通。它只是做了一层异常保证处理。将执行更改提交尝试publicclassThreadExecutor{privatestaticThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(1,1,60,TimeUnit.SECONDS,newArrayBlockingQueue<>(200),newThreadFactoryBuilder().setNameFormat("customThread%d").setUncaughtExceptionHandler((t,e)->System.out.println("UncaughtExceptionHandler捕获到:"+t.getName()+"发生异常"+e.getMessage())).build());@Testpublicvoidtest(){IntStream.rangeClosed(1,5).forEach(i->{try{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}Future>future=threadPoolExecutor.submit(()->{System.out.println("线程"+Thread.currentThread().getName()+"执行");intj=1/0;});try{future.get();}catch(InterruptedExceptione){e.printStackTrace();}catch(ExecutionExceptione){e.printStackTrace();}});}}线程customThread0执行java.util.concurrent.ExecutionException:java.lang.ArithmeticException:/零线程customThread0执行java.util.concurrent.ExecutionException:java.lang.ArithmeticException:/零线程customThread0执行java.util.concurrent.ExecutionException:java.lang.ArithmeticException:/零线程customThread0执行java.util.concurrent.ExecutionException:java.lang.ArithmeticException:/零线程customThread0执行java.util.concurrent.ExecutionException:java.lang.ArithmeticException:/零线程通过submit可以屏蔽线程异常只有在get()的执行结果达到线程复用时才会抛出。原因是通过submit提交的线程在发生异常时会保存异常,直到future.get();才会抛出;这是Futuretask的run()方法的一部分,参见setException:publicvoidrun(){try{Callable
