JAVA线程池CachedThreadPool与FixedThreadPool的简单分析

抛弃了简单的new Thread(),加入了JAVA中的线程池,一路走来满是荆棘。在使用CachedThreadPool与FixedThreadPool发现了一些问题,这里作简要记录。

关于无限长线程池CachedThreadPool

首先上一下Executors.newCachedThreadPool()的源码

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }

关于ThreadPoolExecutor类参数说明,这里就不赘述了,网上很多。
从源码可以看出CachedThreadPool所使用的线程最大数量为Integer.MAX_VALUE,也就是说在执行过程中只要前面的任务没有完成,那么线程数量就不断增加,这样的话会产生大量线程使用过程可能存在栈溢出的问题。

定长线程池FixedThreadPool

下面是Executors.newFixedThreadPool(10);的源码

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

定长线程池限制了最大的线程数量,解决了不定长线程池CachedThreadPool的无限线程的问题。然而定长的线程池使用了无限长的链式阻塞队列,这个队列无限大,如果任务执行慢且内存占用较多时,JVM会产生内存溢出。

个人常用解决方式

为了避免JVM内存问题,本人通常使用以下线程池的方式:

public static ExecutorService getFixedThreadPool(int nThread) {
        return new ThreadPoolExecutor(nThread, nThread,
                0L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(nThread),new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable run, ThreadPoolExecutor executor) {
                        if(!executor.isTerminated())
                            try {
                                executor.getQueue().put(run);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                    }
                });
    }

这里限定线程池大小和阻塞队列的大小,避免线程池的无限增大。然而当
阻塞队列满时,主线程(一般是生产者线程)会阻塞,等待队列中有任务执行完毕后才会继续添加任务,这样可以避免无限增长的线程池和无限增长的阻塞队列。这里唯一的缺陷是主线程需要等待子线程执行才能继续,所以使用时应该视情况而定。

使用ThreadPoolExecutor可以实例化需要的线程池,以上线程池需要看实际的情况来使用!

你可能感兴趣的:(程序开发)