面试官:线程池执行过程中遇到异常会发生什么,怎样处理?

Java技术栈

共 7937字,需浏览 16分钟

 ·

2021-10-13 01:25

点击关注公众号,Java干货及时送达

线程遇到未处理的异常就结束了

这个好理解,当线程出现未捕获异常的时候就执行不下去了,留给它的就是垃圾回收了。

线程池中线程频繁出现未捕获异常

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">当线程池中线程频繁出现未捕获的异常,那线程的复用率就大大降低了,需要不断地创建新线程。

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">做个实验:

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">public class ThreadExecutor {

 private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build());

 @Test
 public void test() {
  IntStream.rangeClosed(1, 5).forEach(i -> {
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   threadPoolExecutor.execute(() -> {
     int j = 1/0;
  });});
 }
}

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">我们把异常捕获试试:

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">public class ThreadExecutor {

 private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build());

 @Test
 public void test() {
  IntStream.rangeClosed(1, 5).forEach(i -> {
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   threadPoolExecutor.execute(() -> {
    try {
     int j = 1 / 0;
    } catch (Exception e) {
     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());
    }
   });
  });
 }
}
 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" data-linktype="2">customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero

 {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {     int j = 1/0;  });}); }}新建一个只有一个线程的线程池,每隔0.1s提交一个任务,任务中是一个1/0的计算。Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)可见每次执行的线程都不一样,之前的线程都没有复用。原因是因为出现了未捕获的异常。我们把异常捕获试试:public class ThreadExecutor { private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,   new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build()); @Test public void test() {  IntStream.rangeClosed(1, 5).forEach(i -> {   try {    Thread.sleep(100);   } catch (InterruptedException e) {    e.printStackTrace();   }   threadPoolExecutor.execute(() -> {    try {     int j = 1 / 0;    } catch (Exception e) {     System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());    }   });  }); }}customThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zerocustomThread 0 / by zero可见当异常捕获了,线程就可以复用了。" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">可见当异常捕获了,线程就可以复用了。另外, 多线程系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。

问题来了,我们的代码中异常不可能全部捕获

如果要捕获那些没被业务代码捕获的异常,可以设置Thread类的uncaughtExceptionHandler属性。这时使用ThreadFactoryBuilder会比较方便,ThreadFactoryBuilder是guava提供的ThreadFactory生成器。

new ThreadFactoryBuilder()
.setNameFormat("customThread %d")
.setUncaughtExceptionHandler((t, e) -> System.out.println(t.getName() + "发生异常" + e.getCause()))
.build()

修改之后:

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()))
     .build());

 @Test
 public void test() {
  IntStream.rangeClosed(1, 5).forEach(i -> {
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }

   threadPoolExecutor.execute(() -> {
    System.out.println("线程" + Thread.currentThread().getName() + "执行");
    int j = 1 / 0;
   });
  });
 }
}
线程customThread 0执行
UncaughtExceptionHandler捕获到:customThread 0发生异常/ by zero
线程customThread 1执行
UncaughtExceptionHandler捕获到:customThread 1发生异常/ by zero
线程customThread 2执行
UncaughtExceptionHandler捕获到:customThread 2发生异常/ by zero
线程customThread 3执行
UncaughtExceptionHandler捕获到:customThread 3发生异常/ by zero
线程customThread 4执行
UncaughtExceptionHandler捕获到:customThread 4发生异常/ by zero

可见,结果并不是我们想象的那样,线程池中原有的线程没有复用!所以通过UncaughtExceptionHandler想将异常吞掉使线程复用这招貌似行不通。它只是做了一层异常的保底处理。

推荐一个 Spring Boot 基础教程及实战示例:https://www.javastack.cn/categories/Spring-Boot/

将excute改成submit试试

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()))
     .build());

 @Test
 public void test() {
  IntStream.rangeClosed(1, 5).forEach(i -> {
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }

   Future future = threadPoolExecutor.submit(() -> {
    System.out.println("线程" + Thread.currentThread().getName() + "执行");
    int j = 1 / 0;
   });
   try {
    future.get();
   } catch (InterruptedException e) {
    e.printStackTrace();
   } catch (ExecutionException e) {
    e.printStackTrace();
   }
  });
 }
}
线程customThread 0执行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
线程customThread 0执行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
线程customThread 0执行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
线程customThread 0执行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
线程customThread 0执行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

通过submit提交线程可以屏蔽线程中产生的异常,达到线程复用。当get()执行结果时异常才会抛出。

原因是通过submit提交的线程,当发生异常时,会将异常保存,待future.get();时才会抛出。最新面试题整理好了,点击Java面试库小程序在线刷题。

这是Futuretask的部分run()方法,看setException:

public void run() {
    try {
        Callable c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } 
}

protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

将异常存在outcome对象中,没有抛出,再看get方法:

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

当outcome是异常时才抛出。

总结

1、线程池中线程中异常尽量手动捕获

2、通过设置ThreadFactory的UncaughtExceptionHandler可以对未捕获的异常做保底处理,通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出。

本文链接:https://blog.csdn.net/weixin_37968613/article/details/108407774

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。





关注Java技术栈看更多干货



获取 Spring Boot 实战笔记!
浏览 26
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报