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

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单独内部判断处理

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_26437925/article/details/127463372
今日推荐