线程池处理任务,异常处理

85 阅读2分钟

文章目录

线程池处理任务,异常处理

前言

业务开发中我们使用线程池或者线程处理任务,异常如何处理,线程并不像平时try…catch那样捕获。

异常处理

Thread中,提供了一个返回线程异常的一个方法

    Thread r = new Thread(run);
            
            r.setUncaughtExceptionHandler((t, e) -> {
                System.out.println(t.getName() + " - " + " 失败 ... ");
                e.printStackTrace();
                System.out.println(" =================== ");
            });

我们可以打印出线程运行中的异常

而在线程池中,我们如何获取?

自定义线程池时,指定线程的异常管理器

代码实例如下:

        MyThreadFactory myThreadFactory = new MyThreadFactory();

        ThreadPoolExecutor executorService =
                new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS,
                        new ArrayBlockingQueue<>(30),
                        myThreadFactory);
        for (int i = 0; i < 20; i++) {
            executorService.execute(() -> {
                int n = 1 / 0;
            });
        }


        System.out.println(" ---- main ----- ");
        executorService.awaitTermination(100, TimeUnit.SECONDS);

        //executorService.shutdown();
    }


    private static class MyThreadFactory implements ThreadFactory {

        private static final AtomicInteger a = new AtomicInteger();

        @Override
        public Thread newThread(Runnable run) {

            Thread r = new Thread(run);
            r.setName("thread -" + a.getAndIncrement());
            r.setUncaughtExceptionHandler((t, e) -> {
                System.out.println(t.getName() + " - " + " 失败 ... ");
                e.printStackTrace();
                System.out.println(" =================== ");
            });
            return r;
        }
    }

此时,就可以打印出每个线程的异常

但是,有些场景,我们在使用线程池时,如果业务代码执行异常,或者没成功。
可能我们需要记录数据,或者重新操作等。需要保存一个标识等等,此时这种异常就不适合我们

由于执行的是runable 我们可以自定义一个runable模板,代码如下


        //模板处理异常
        ExecutorService executorService2 = Executors.newFixedThreadPool(4,new MyThreadFactory());

        IntStream.rangeClosed(1, 10).boxed().forEach(x -> {

            // 处理任务,返回处理状态
            executorService2.execute(
                    new MyTask(x) {
                    @Override
                    protected void error(Throwable e) {
                        if (x % 3 == 0) {
                            System.out.println(x + "  --->  任务 error " + e.getMessage());
                        }

                    }

                    @Override
                    protected void doExecute() {
                        System.out.println(x + "  --->  任务 error ");
                    }

                    @Override
                    protected void done() {
                        System.out.println(x + "  --->  任务 done ");
                    }

                    @Override
                    protected void doInit() {
                    }

            });
        });


        executorService2.shutdown();
        executorService2.awaitTermination(50, TimeUnit.SECONDS);

        System.out.println(" ================ ");

    }

    private static class MyThreadFactory implements ThreadFactory {

        private static final AtomicInteger a = new AtomicInteger();

        @Override
        public Thread newThread(Runnable run) {

            Thread r = new Thread(run);
            r.setName("thread -" + a.getAndIncrement());
            r.setUncaughtExceptionHandler((t, e) -> {
                System.out.println(t.getName() + " - " + " 失败 ... ");
                e.printStackTrace();
                System.out.println(" =================== ");
            });
            return r;
        }
    }

    private abstract static class MyTask implements Runnable {


        private final int no;

        protected MyTask(int no) {
            this.no = no;
        }

        @Override
        public void run() {
            //System.out.println(" ======= MyTask  run ========= ");
            doInit();
            try {
                doExecute();
                done();
            }catch (Throwable e){
                error(e);
            }



        }

        protected abstract void error(Throwable e);

        protected abstract void doExecute();

        protected abstract void done();


        protected abstract void doInit();

    }

可以看到通过这种模板方法可以在任务里面处理异常

1 —> 任务 error
2 —> 任务 error
1 —> 任务 done
2 —> 任务 done
3 —> 任务 error
3 —> 任务 done
4 —> 任务 error
4 —> 任务 done
5 —> 任务 error
5 —> 任务 done
6 —> 任务 error
9 —> 任务 error
8 —> 任务 error
8 —> 任务 done
7 —> 任务 error
10 —> 任务 error
10 —> 任务 done
9 —> 任务 done
6 —> 任务 done
7 —> 任务 done
================

其他知识点

Java 多线程基础
深入理解aqs
ReentrantLock用法详解
深入理解信号量Semaphore
深入理解并发三大特性
并发编程之深入理解CAS
深入理解CountDownLatch
Java 线程池