JAVA并发编程:Executors

生活

为什么我们总是问为什么?

前言

JAVA的开发人员,大概是认为我们这种JAVA的使用者太蠢了,所以给我们预先提供了三个现成的线程池。现在就来剖析下,注意,都在Executors类下。

newFixedThreadPool

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

从源码看到,传入的核心线程数与最大线程数一致,且使用到的阻塞队列式LinkedBlockingQueue.
从我们上一篇学习的ThreadPoolExecutor可大致分析出这个线程池的特性:
提交一个任务进来,如果当前工作线程数小于核心线程数,就直接新建一个工作线程。
当当前工作线程数等于核心线程数就进去队列等待,由于LinkedBlockingQueue是无界的,所以这个队列永远不会满,当队列中有任务时,工作线程数永远等于核心线程数。所以事实上最大线程数还有空闲超时限制都已经没有用了。

这种类型的线程池可以适用CPU密集的工作,在这种工作中CPU忙于计算而很少空闲,由于CPU能真正并发的执行的线程数是一定的(比如四核八线程),所以对于那些需要CPU进行大量计算的线程,创建的线程数超过CPU能够真正并发执行的线程数就没有太大的意义。

优点:所有任务都保证会被执行,不会拒绝任何任务
缺点:由于队列数量没有限制,在长时间执行时间的情况下可以造成内存的问题

newSingleThreadExecutor

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

这是一个任务要求单线程执行的线程池,跟上面的是一样的,只是把核心线程数和最大线程数都换成1,同时通过FinalizableDelegatedExecutorService来包装,屏蔽对核心线程数的修改,也同样使用了无界并发队列 LinkedBlockingQueue.
适用于逻辑上需要单线程执行的线程。
优缺点如上。

newCachedThreadPool

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

如上newCachedThreadPool ,
这个线程池的参数 核心线程数0,最大线程数无限大,使用SynchronousQueue队列,这个队列在前面学习过,它是一个无法存储元素的队列,当他存放一个元素进来就会阻塞直到另一个线程进来取走。
因此通过ThreadPoolExecutor的学习可以了解到newCachedThreadPool的运作,当一个任务提交进来,由于核心线程数为0,因此尝试提交给队列,通过offer去提交,快速返回false,在判断是否超过最大线程数,因最大线程数无限大,所以这个线程池是只要任务进来就马上给他分配一个线程去执行的。
这种类型的线程池非常适用IO密集的服务,因为IO请求具有密集、数量巨大、不持续、服务器端CPU等待IO响应时间长的特点。服务器端为了能提高CPU的使用率就应该为每个IO请求都创建一个线程,以免CPU因为等待IO响应而空闲。
缺点:在任务执行时间无限延长的极端情况下会创建过多的线程。

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/84933652