大话线程池原理

1.前言

  一开始很犹豫这要不要写这篇文章,在网上看了不少文章写的都很不错,可是秉持着更全更易懂的原则,仍是打算本身整理一篇。也参考了不少的文章博客,但愿这篇文章可以真正的帮到你。(同时吐槽下,稀土掘金就不能增长一个分类专区的功能吗,这样博客写多了,很差归类的)java

2.为毛用它

  1. 下降资源消耗:经过它重用已存在的线程,能够有效的下降,由频繁建立和销毁线程所形成资源的消耗。
  2. 增长系统稳定性:由线程池统一管理,除了能够下降资源的消耗,还能够有效控制线程的并发数量,不会让线程无限制的建立,增长了系统的稳定性。
  3. 提升了响应速度:由于重用线程,因此提升了响应速度。

3.线程池介绍

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 复制代码

1. corePoolSize(最大核心线程数):

  线程池建立线程的时候,若是当前的线程总个数 < corePoolSize,那么新建的线程为核心线程,若是当前线程总个数 >= corePoolSize,那么新建的线程为非核心线程。   核心线程默认会一直存活下去,即使是空闲状态,可是若是设置了allowCoreThreadTimeOut(true)的话,那么核心线程空闲时间达到keepAliveTime也将关闭。缓存

2. maximumPoolSize(线程池能容纳的最大线程数量):

  核心线程数 + 非核心线程数 = 最大线程数量微信

3. keepAliveTime(线程的存活时间):

  非核心线程在空闲状态下,超过keepAliveTime时间,就会被回收,若是核心线程设置了allowCoreThreadTimeOut(true)的话,那么在空闲时,超过keepAliveTime时间,也会被回收。并发

4. TimeUnit(时间单位):

  时、分、秒、毫秒等ide

5. BlockingQueue(缓存队列):

  当有任务到来时,会指派给核心线程去执行,等核心线程都被占用了,那么再有新的任务,就会加入到队列中,等队列满了,再有任务,就再启动非核心线程去执行。经常使用的队列以下spa

  • SynchronousQueue   使用这个队列时,当有任务到来的时候,它并不存任务,而是直接将任务丢给线程去执行,若是线程都在被占用,它就会建立线程去处理这个任务,因此通常使用这个缓存队列的时候,maximumPoolSize(线程池能容纳的最大线程数量)设置到 Integer.MAX_VALUE,否则任务数超过maximumPoolSize限制而建立不了线程。线程

  • LinkedBlockingQueue   使用这个队列是,当有任务到来的时候,若是当前的核心线程数 < corePoolSize,它会新建核心线程去执行任务,若是当前核心线程数 >= corePoolSize时,它会将还未被执行的任务存储起来,等待执行,可是这个队列,没有存储上限,因此尼,这也就形成了,maximumPoolSize(总线程数),永远不会超过corePoolSize。此队列按 FIFO(先进先出)原则对任务进行操做。3d

  • ArrayBlockingQueue   使用这个队列尼,能够设置队列的长度,那么当任务到来的时候,核心线程数 < corePoolSize时, 则建立核心线程去执行任务,若是核心线程数 >= corePoolSize时,加入到队列里面,等待执行,若是队列也满了,则新建非核心线程去执行任务。此队列按 FIFO(先进先出)原则对元素进行操做。可是线程数不能超过总线程数。code

  • DelayQueue(延时队列)   任务到来时,首先先加入到队列中,只有达到了指定的延时时间,才会执行任务。cdn

5. ThreadFactory(线程工厂):

  用来建立线程池中的线程,用默认的便可。

6. RejectedExecutionHandler(拒绝策略):

  当任务过多时,即:当前线程数已经达到了最大线程数,缓冲队列也已经满了,或者线程池关闭了,那么再来的任务请求,咱们会拒绝,怎么拒绝尼?有如下几个方案:

  • AbortPolicy(默认策略)

  “当你有了,原配,想再娶个小三时,原配的态度”,默认策略,简单粗暴,直接拒绝抛异常(RejectedExecutionException)

  • DiscardPolicy

  “原配的太粗暴,无法子,只能把小三的电话,微信都删掉了,不再来往了”,DiscardPolicy策略就是,直接丢弃,可是不抛异常。若是线程队列已满,则后续提交的任务都会被丢弃。

  • DiscardOldestPolicy

  “可是原配看久了,很腻了,算了,人生短短几十年,何须委屈本身,休妻,腾地方,娶小三”,DiscardOldestPolicy策略就是,直接丢弃掉队伍最前面的任务,再从新提交后面新来的任务。

  • CallerRunsPolicy

      “唉,原配虽然很差看,可是家里有背景,不敢随意抛弃,后面的小三仍是哪来的回哪去吧,找个熟人照顾着”,CallerRunsPolicy策略就是不抛弃任务,由调用者运行这个任务,好比主线程启动了线程池去运行这个任务,如今线程池满了,那么这个任务就由主线程进行调用执行了。

总结一下 让任务到来的时候,会执行如下的流程

  1. 线程数量未达到 corePoolSize,则新建一个线程(核心线程)执行任务。
  2. 线程数量达到了 corePoolsSize,则将任务移入队列等待。
  3. 队列已满,新建非核心线程(先进先出)执行任务。
  4. 队列已满,总线程数又达到了 maximumPoolSize,就会由 RejectedExecutionHandler 抛出异常。

明白了吗?若是你不想本身写一个线程池,有更简单的方式,就是系统已经为咱们定义好了几个线程池,下面介绍下他们的使用,看看有没有符合你要求的,。


4.经常使用的线程池

看下图


5.代码

1. FixedThreadPool

建立一个定长的线程池,可控制线程最大的并发数,超出的部分任务,会在队列中等待,适用于:已知并发压力的状况下,对线程数作限制。实际上就是只使用核心线程。

private void testFiexdThreadPool() {

        ExecutorService threadPool = Executors.newFixedThreadPool(3);

        for (int n = 0; n < 10; n++){

            final int finalN = n;
            threadPool.execute(new Runnable() {

                @Override
                public void run() {

                    System.out.println(Thread.currentThread().getName()+":"+ finalN);
                }
            });
        }
    }
复制代码

结果

2. SingleThreadExecutor

建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。

private void testSingleThreadExecutor(){

    ExecutorService threadPool = Executors.newSingleThreadExecutor();
    for (int n = 0; n < 10; n++){

        final int finalN = n;
        threadPool.execute(new Runnable() {

            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+":"+ finalN);
            }
        });
    }
}
复制代码

结果

3. CachedThreadPool

建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。

private void testCachedThreadPool(){

    ExecutorService threadPool = Executors.newCachedThreadPool();

    for (int n = 0; n < 10; n++){

        final int finalN = n;
        threadPool.execute(new Runnable() {

            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+":"+ finalN);
            }
        });
    }
}
复制代码

结果

4. ScheduledThreadPool

建立一个可按期或者延时执行任务的定长线程池,支持定时及周期性任务执行。

private void testScheduledThreadPool(){

    ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);

    for (int n = 0; n < 10; n++){

        final int finalN = n;
        threadPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+":"+ finalN);
            }
        }, 3, 2, TimeUnit.SECONDS);
    }
}
复制代码

结果

相关文章
相关标签/搜索