美文网首页
线程池中的线程异常

线程池中的线程异常

作者: virtual灬zzZ | 来源:发表于2021-03-29 17:47 被阅读0次

一个线程池中的线程异常了,那么线程池会怎么处理这个线程?

首先进行模拟,

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

public class ExecutorsTest {
    public static void main(String[] args) {
        ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();
        executorService.execute(() -> sayHi("execute"));
        Future<?> submit = executorService.submit(() -> sayHi("submit"));
        try {
            submit.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    private static void sayHi(String name) {
        String printStr = "【thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "】";
        System.out.println(printStr);
        throw new RuntimeException(printStr + ",抛出异常!!");
    }

    private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();
        executorService.setThreadNamePrefix("(ThreadTest)-");
        executorService.setCorePoolSize(5);
        executorService.setMaxPoolSize(10);
        executorService.setQueueCapacity(1000);
        executorService.setKeepAliveSeconds(30);
        executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executorService.initialize();
        return executorService;
    }
}

结果如下:

Exception in thread "(ThreadTest)-1" java.lang.RuntimeException: 【thread-name:(ThreadTest)-1,执行方式:execute】,抛出异常!
    at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.sayHi(ExecutorsTest.java:25)
    at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.lambda$main$0(ExecutorsTest.java:10)
    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:745)
【thread-name:(ThreadTest)-1,执行方式:execute】
【thread-name:(ThreadTest)-2,执行方式:submit】

由结果可见

当执行方式是execute时,可以看到堆栈异常的输出。

当执行方式是submit时,堆栈异常没有输出。
  • 当执行方式是executes时:

java.util.concurrent.ThreadPoolExecutor#runWorker中抛出了异常:

QQ图片20210329113715.png

java.lang.ThreadGroup#uncaughtException进行了异常处理:

QQ图片20210329114522.png

这个方法是JVM调用的,我们只需要指定我们想要的处理方式即可。

那我们怎么指定呢:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class test {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            throw new RuntimeException("runtimeEx");
        };


        //直接new Thread()的时候
        Thread t = new Thread(runnable);
        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("hahha=" + e.getMessage());
            }
        });

        t.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //线程池的时候:
        ExecutorService threadPool = Executors.newFixedThreadPool(2, r -> {
            Thread temp = new Thread(r);
            temp.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println("hahhapool=" + e.getMessage());
                }
            });
            return temp;
        });

        threadPool.execute(runnable);
    }
}

运行结果:
hahha=runtimeEx
hahhapool=runtimeEx

  • 当执行方式是submit时:

QQ图片20210329164810.png
其本质也是调用了execute方法,所以它还是回到java.util.concurrent.ThreadPoolExecutor#runWorker方法:

不影响其他线程任务

ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();
        executorService.execute(() -> sayHi("execute"));
        //executorService.submit(() -> sayHi("submit"));

        Future<?> submit = executorService.submit(() -> sayHi("submit"));
        try {
            submit.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        executorService.execute(() -> sayHi("55"));

        executorService.execute(() -> sayHi("execute1"));

        executorService.execute(() -> sayHi("execute2"));

结果:

【thread-name:(ThreadTest)-2,执行方式:submit】
【thread-name:(ThreadTest)-5,执行方式:execute2】
Exception in thread "(ThreadTest)-3" java.lang.RuntimeException: 【thread-name:(ThreadTest)-3,执行方式:55】,抛出异常!
    at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.sayHi(ExecutorsTest.java:35)
    at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.lambda$main$2(ExecutorsTest.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:745)
【thread-name:(ThreadTest)-4,执行方式:execute1】
【thread-name:(ThreadTest)-1,执行方式:execute】

线程池中一个线程异常了后,不影响其他线程任务

大家注意线程名称这个细节:1,2,3,4,6。魔鬼都在细节里啊,这个点我下面会讲,先在这里把问题抛出来:我就纳闷了,怎么没有5啊?!

这个线程会被放回线程池为啥全错了?
我们去源码里面寻找答案:

让源码给出答案:

5号线程去哪里了?

new Worker()方法会告诉你:5去哪里了。

再配上这张由我这个灵魂画师亲自操刀画的图,一起食用,味道更佳:

现在我们知道为啥:我回答这个线程会被放回线程池为啥全错了吧。还附送你一个线程名称变化的细节,不客气,关注一下就好。

当一个线程池里面的线程异常后:

当执行方式是execute时,可以看到堆栈异常的输出。

当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常。

不会影响线程池里面其他线程的正常执行。

线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。

https://blog.csdn.net/javachengzi/article/details/108733679

相关文章

  • 线程池中的线程异常

    一个线程池中的线程异常了,那么线程池会怎么处理这个线程? 首先进行模拟, 结果如下: 由结果可见 当执行方式是ex...

  • # Java实战系列 - 线程池中的线程出现异常

    问题:线程池中的线程执行任务出现异常,该线程接下来的命运如何? 结论:线程会结束,线程池会新建线程替换该线程 验证...

  • 线程池几个重要参数

    corePoolSize 线程池中常驻线程核心线程数 maximumPoolSize 线程池中同时容纳可执行的线程...

  • Java线程池异常处理

    起因 在Java默认的线程池中执行的程序,如果程序产生异常导致线程池里面的线程死掉,完全没有任何信息抛出来,这个是...

  • 线程池中的线程在执行过程中发生异常的处理措施

    线程池中的一个线程异常了会被怎么处理? 抛异常出来并打印在控制台上(只对了一半,根据提交方式的不同(execute...

  • Java多线程处理大数据量

    这里使用CountDownLatch 来使主线程等待线程池中的线程执行完毕。

  • 四种线程池

    使用线程池可以给我们带来很多好处,首先通过线程池中线程的重用,减少创建和销毁线程的性能开销。其次,能控制线程池中的...

  • Android线程池 ThreadPoolExecutor

    一.ThreadPoolExecutor的构造方法 corePoolSize 程池中的核心线程数,也就是是线程池中...

  • 线程池中Callable异常处理分析

    前言   分析前几天遇到的一个老代码留下的坑。线程池中运行Callable线程时抛出的异常捕获不到,简化的逻辑如图...

  • 3. Interview-JUC

    1 线程池原理 1.1 ThreadPoolExecutor构造器 corePoolSize:线程池中的线程数量 ...

网友评论

      本文标题:线程池中的线程异常

      本文链接:https://www.haomeiwen.com/subject/yiovhltx.html