Java提供的四种线程池

简介

推荐使用线程池来代替单独创建线程。多用于处理非常多的请求的时候,如果每个请求都去开启一个线程的话,系统需要不停的对线程进行创建和销毁,比线程真正执行的时间长,增加系统开销。

Java自身提供了四种线程池来实现一些功能。

线程池 简单解释
newSingleThreadExecutor

只有一个线程在工作,其它任务放到缓存队列中。相当于单线程串行执行所有任务。当有异常结束,则会创建新的线程

newFixedThreadPool 创建固定大小的线程池,每提交任务则创建线程,直到设置值,其它任务放到缓存队列中。当有异常结束,则会创建新的线程
newCachedThreadPool 一个缓冲池,任务提交就创建线程,超过60s就回收线程。无界线程。OkHttp就是采用的这种方式来管理发送的请求。
newScheduledThreadPool 创建一个定长线程池,可以定时及周期性任务执行

newSingleThreadExecutor

构造函数:从设置参数可以看出是corePoolSize只有1,并且缓存队列为无界队列。

    public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

项目中实例化:

    private static void singleExecutor(){
        ExecutorService executor = Executors.newSingleThreadExecutor();
        execute(executor);
    }

执行6个任务的时

任务1加入到核心队列中执行,其他2~6放到缓存队列中
等任务1完成之后,从缓存队列中取出2,执行
直到6个任务全都执行完毕

运行结果如下:

1 is running... 
1 is end !!! 
2 is running... 
2 is end !!! 
3 is running... 
3 is end !!! 
4 is running... 
4 is end !!! 
5 is running... 
5 is end !!! 
6 is running... 
6 is end !!! 

newFixedThreadPool

构造函数:从设置参数可以看出是corePoolSize和maximumPooSize大小一样,并且缓存队列为无界队列。所以就只有核心线程存在,超过设置的任务个数,则会放入到缓存队列中,不会创建新的线程。

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

项目中实例化:

    private static void fixedExecutor(){
        ExecutorService executor = Executors.newFixedThreadPool(2);
        execute(executor);
    }

执行6个任务的时

任务1和2在核心线程中执行,其它的3~6放倒缓存队列中
任务1和2执行完,从缓存队列中拿出3和4执行
任务3和4执行完,从缓存队列中拿出5和6执行

 执行结果如下:

1 is running... 
2 is running... 
2 is end !!! 
1 is end !!! 
3 is running... 
4 is running... 
4 is end !!! 
3 is end !!! 
6 is running... 
5 is running... 
5 is end !!! 
6 is end !!! 

newCachedThreadPool

构造函数:从设置参数可以看出是corePoolSize为0,maximumPooSize为Integer.MAX_VALUE,没有核心线程,来任务就创建线程,线程超过60s空闲则回收。

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

项目中实例:

    private static void cacheExecutor(){
        ExecutorService executor = Executors.newCachedThreadPool();
        execute(executor);
    }

执行6个任务的时

任务1~6一起执行
都执行完毕之后,线程超过60s之后,线程回收

执行结果如下:

1 is running... 
3 is running... 
2 is running... 
4 is running... 
5 is running... 
6 is running... 
1 is end !!! 
4 is end !!! 
5 is end !!! 
6 is end !!! 
2 is end !!! 
3 is end !!! 
Process finished with exit code 0

这里多说几句话: ThreadPoolExecutor里的keepAliveTime这个参数,指的是线程池中超过corePoolSize数目的空闲线程的最大存活时间,也就是除去核心线程之外创建的线程,并不是核心线程,默认的核心线程不会自动回收。所以注意下使用ThreadPoolExecutor的时候,资源释放 的问题,我想改天研究下这里。。

如果让核心线程空闲的时候也回收的话,可以通过设置allowCoreThreadTimeOut(true),线程池中core线程空闲时间达到keepAlive时,也将关闭。

newScheduledThreadPool

构造函数:从设置参数可以看出是corePoolSize为设置的参数,maximumPooSize为Integer.MAX_VALUE,默认的线程keep-alive的时间为10ms(这里设置之所以为10ms,是为了防止调用者在使用该方法的时候设置corePoolSize为0,若为0,keep-alive也为0的话,会停止,当然如果keep-alive设置的时间太长的话,也不利于线程的回收)。

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

   public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }
   private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;

项目中实例化,要与ScheduledExecutorService配合使用:

    private static void scheduledExecutor(){
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
        executor.scheduleAtFixedRate(new NameRunnable(1),1L,3L, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(new NameRunnable(2),1L,3L, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(new NameRunnable(3),1L,3L, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(new NameRunnable(4),1L,3L, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(new NameRunnable(5),1L,3L, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(new NameRunnable(6),1L,3L, TimeUnit.SECONDS);
    }

执行6个任务的时:

开始会执行任务1和2(设置的coreSize为2),剩余的3~6加入到到缓存队列中
执行完1和2之后,在从队列中取3和4,依次类推
当5和6执行完毕之后,又回从1和2开始执行

执行结果如下:

2 is running... 
1 is running... 
1 is end !!! 
2 is end !!! 
3 is running... 
4 is running... 
3 is end !!! 
4 is end !!! 
5 is running... 
6 is running... 
5 is end !!! 
6 is end !!! 
1 is running... 
2 is running... 
2 is end !!! 
1 is end !!! 
3 is running... 
4 is running... 
4 is end !!! 
3 is end !!! 
5 is running... 
6 is running... 
 

结束语

在实际项目中,还是建议自行通过new ThreadPoolExecutor的设置其构造方法的方式来创建线程,这样可以更能明确线程池的运行规则,避免资源耗尽,较少风险。

猜你喜欢

转载自blog.csdn.net/nihaomabmt/article/details/81670226