线程池中某个线程执行有异常,该如何处理?

Posted master-dragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池中某个线程执行有异常,该如何处理?相关的知识,希望对你有一定的参考价值。

目录

1. 线程池抛出异常代码

class Task implements Runnable

    @Override
    public void run() 
        System.out.println("task start...");
        int i = 1 / 0;
        System.out.println("task end...");
    


class MyThreadFactoryTest implements ThreadFactory 
    private final AtomicInteger count = new AtomicInteger(0);

    @Override
    public Thread newThread(Runnable r) 
        int c = count.incrementAndGet();
        Thread t = new Thread(r);
        t.setName("MyThreadFactory.thread." + c);
        return t;
    


public class Tmp 

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(1, new MyThreadFactoryTest());
        executorService.submit(new Task());
        executorService.execute(new Task());
        executorService.shutdown();
    


输出:

executorService.submit 没有打印出异常

使用future可以打印,如下

submit 底层仍然是执行execute,只不过封装了一层future,所以需要future.get()才能进行异常捕获和处理

2. 如何获取和处理异常

方法1: 线程自身打印异常

方法2: 使用Thread.setUncaughtExceptionHandler设置线程自己的异常处理

如果要求每个任务都自主加上try ... catch...显然不太合适,无法要求每个人,就自己做改变吧…


class Task implements Runnable

    @Override
    public void run() 
        System.out.println("task start...");
        int i = 1 / 0;
        System.out.println("task end...");
    


class MyThreadFactoryTest implements ThreadFactory 
    private final AtomicInteger count = new AtomicInteger(0);

    @Override
    public Thread newThread(Runnable r) 
        int c = count.incrementAndGet();
        Thread t = new Thread(r);
        t.setName("MyThreadFactory.thread." + c);
        t.setUncaughtExceptionHandler((thread, e)->
            System.out.println("线程工厂设置ExceptionHandler:"+thread.getName() + ":" + e);
        );
        return t;
    


public class Tmp 

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(1, new MyThreadFactoryTest());
        // 仍然无打印
        executorService.submit(new Task());
        // 被线程工厂设置ExceptionHandler捕获到异常
        executorService.execute(new Task());
        executorService.shutdown();
    


附:java.util.concurrent.ThreadPoolExecutor#runWorker

通过阅读源码,execute一个任务,如果能成功执行,会被封装成一个worker,然后执行runWorker方法

final void runWorker(Worker w) 
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try 
            while (task != null || (task = getTask()) != null) 
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try 
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try 
                        //线程执行 
                        task.run();
                        // 各种异常捕获
                     catch (RuntimeException x) 
                        thrown = x; throw x;
                     catch (Error x) 
                        thrown = x; throw x;
                     catch (Throwable x) 
                        thrown = x; throw new Error(x);
                     finally 
                    	// 执行完的处理,可以看到有补货到的异常
                        afterExecute(task, thrown);
                    
                 finally 
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                
            
            completedAbruptly = false;
         finally 
            processWorkerExit(w, completedAbruptly);
        
    

方法3: 重写线程池的afterExecute方法

当然Thread.setUncaughtExceptionHandler仍然有效

class Task implements Runnable

    @Override
    public void run() 
        System.out.println("task start...");
        int i = 1 / 0;
        System.out.println("task end...");
    


class MyThreadFactoryTest implements ThreadFactory 
    private final AtomicInteger count = new AtomicInteger(0);

    @Override
    public Thread newThread(Runnable r) 
        int c = count.incrementAndGet();
        Thread t = new Thread(r);
        t.setName("MyThreadFactory.thread." + c);

        return t;
    


public class Tmp 

    public static void main(String[] args) 
        ExecutorService executorService =  new ThreadPoolExecutor(2, 10,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new MyThreadFactoryTest())
            @Override
            protected void afterExecute(Runnable r, Throwable t) 
                System.out.println("afterExecute:" + Thread.currentThread().getName() + ":" + t);
            
        ;
        // 仍然无打印
        executorService.submit(new Task());
        // 被线程工厂设置ExceptionHandler捕获到异常
        executorService.execute(new Task());
        executorService.shutdown();
    


submit的任务afterExecute单独内部判断处理

以上是关于线程池中某个线程执行有异常,该如何处理?的主要内容,如果未能解决你的问题,请参考以下文章

京东二面:线程池中的线程抛出了异常,该如何处理?大部分人都会答错!

面试官:线程池中线程抛了异常,该如何处理?

JAVA 线程池之Callable返回结果

线程池中断 任务如何处理

Show proceslist时发现大量的sleep,有啥风险吗,该如何处理?

突如其来的“中断异常”,我(Java)该如何处理?