java 的 ExecutorService类线程池 RejectedExecutionException异常

版权声明:禁止CV操作 https://blog.csdn.net/H44341466/article/details/86623722

从java5开始,java官方推荐我们使用并发包下的Executors来处理多线程;

Executors下面一共给我们提供了4种类型的线程池:

1:固定长度的线程池

   public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }

先看下官方注释:
创建一个线程池,该线程池重用固定数量的线程操作一个共享的无界队列。在任何时候,你的线程数都不会超过你设定的线程池的大小,如果所有的线程都处于活动状态,这时候如果有新任务提交,则会进入队列中等待,直到有任务释放线程,如果有线程由于失败终止,那么会另外开辟一个线程来替代原来失败的线程。
另外最重要的一点,这个线程池中的线程不会自动关闭,需要你手动关闭。

2: 单一线程池

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

这个就是创建一个单一的线程执行任务,如果这个单线程在执行之前由于失败而终止,则会有一个新的线程取代它执行后续任务,来保证任务的顺序执行;

3:缓冲线程池

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    缓冲线程池是可以动态创建的,每来一个任务就会开辟一个线程,如果之前开辟的线程任务执行完,这这个释放的线程又可以用来执行新的任务,理论上可以创建2的29次方个线程(java中设置了32位的值,后4位标识线程状态,前29位记录线程数量)。
 当一个线程超过60秒的未使用,则该线程将被终止并从缓存中删除。因此,一个空闲时间足够长的池不会消耗任何资源。

4:定时线程

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

创建一个线程池,该线程池可以调度在之后运行的命令来延迟执行,或周期性执行。
同样的你设定的corePoolSize这些线程不会自动回收,会一直存在内存中。

好了,下面介绍下自己遇到的一个小问题,其实是因为粗心,没有注意,因为我这个业务是周期执行;所以,在程序中我手动执行了shutdown()方法,而导致了错误,首先看下我自己定义的线程池类;

public enum ThreadPoolUtil {

    INSTANCE;

    private ExecutorService newCachedThreadPool = null;

    private ThreadPoolUtil () {
        newCachedThreadPool = Executors.newCachedThreadPool();
    }

    public ExecutorService getInstance() {
        return newCachedThreadPool;
    }
}

这里我用的是缓存线程池;

业务代码大概是这样

 List<KingdeePaymentPlanRst> newtLst = paymentPlanRstList.subList(i, i + toIndex);
                Future<Set<String>> future = threadPool.submit(new Callable<Set<String>>() {
                    @Override
                    public Set<String> call() {
                        return kingdeePmentPlanSync(newtLst, succCnt, failCnt);
                    }
                });
                futures.add(future);

这是调用业务的代码段,但是问题就出在下面这个地方:

}finally {
            //关闭线程池
//            threadPool.shutdown();
        }

我在try catch的finally手动关闭了线程池,第一次执行没有问题,当下一次轮询的时候,由于我已经把线程池关闭,导致后续的线程添加不进来,然后报了RejectedExecutionException 拒绝异常;

因为我用的是缓存线程池,其实就算不关闭,jvm也会在任务执行完后60自动帮我们关闭。

大概就是这个情况,mark一下;防止再犯;

猜你喜欢

转载自blog.csdn.net/H44341466/article/details/86623722