• java线程池ThreadPoolExecutor


    1 submit的Runnable为什么通过Future获取任务的执行结果

    submit的Runnable被封装成了FutureTask对象,并且返回。

    Runnable执行的结果是在哪里交给FutureTask的?

    FutureTask重写了Runnable的run()方法,在这个run()方法中,将任务的返回值放在了FutureTask的outcome成员中。

    这样在主线程中就可以获取到该任务的执行结果了。

    如果想要获取任务真正的执行结果得传入一个Callable类型的任务,而不能是Runnable类型的任务。如果传入Runnable类型的任务,就算给了一个返回值,也不是Runnable任务的返回值,而就是这个指定的返回值。

    2 beforeExecute和afterExecute有什么用

    beforeExecute是在任务执行之前执行的,afterExecute是在任务执行之后执行的,可以在里面添加日志、监控、统计信息。比如统计各个线程的执行时间等。

    3 线程池的任务队列

     线程池的任务队列就是一个BlockingQueue,可以是ArrayBlockingQueue,这个时候任务队列是固定大小的,如果任务过多的话,就会出现处理不了的情况。

    线程池的任务队列的数据是自己设置的。

    4 线程池的线程数目

    4.1 corePoolSize 

    向线程池添加新的任务的时候,如果线程数小于corePoolSize的时候,就会为该任务新创建一个线程。

    如果allowCoreThreadTimeOut没有设置的话,该线程池至多有corePoolSize这么多的线程可以一直idle状态而不退出。

    4.2 maximumPoolSize

    maximumPoolSize是线程池中允许的最大线程数。

    4.3 keepAliveTime

    如果设置了allowCoreThreadTimeOut的话,所有的线程在没有任务的时候最多的生存时间,如果超过了keepAliveTime的话,就会被销毁。

    如果没有设置allowCoreThreadTimeOut的话,核心线程是不受该值影响的。超过了corePoolSize的线程会有一个keepAliveTime的生存时间,超过了该时间没有新的任务的话,该线程会被销毁。

    5 works集合和workQueue

    works集合是线程池中的线程集合;workQueue是被挂起的任务集合。 

    5.1 workQueue的大小

    如果是ArrayBlockingQueue,在创建线程池的时候,需要指定这个值。

    5.2 works集合的大小

    corePoolSize和maximumPoolSize配置的。

    6  workQueue中等待的任务是如何被works消费掉的

     每个worker的run()方法本质上是调用了runWorker函数,在这个函数中有一个while循环,不断的去workQueue中获取新的任务执行。如果workQueue中没有新的任务了,有两个情况,如果配置为不timeout的话,核心线程会在阻塞队列上睡眠,等待新的任务的到来;如果配置了timeout的话,核心线程会退出,以后有新的任务的时候再创建。

    当ThreadPoolExecutor调用execute加入新的任务的时候,如果works不够corePoolSize的话又回新建新的线程到线程池。

    也就是说,ThreadPoolExecutor的execute是生成者,不断加入新的任务,而每个work即每个线程的runWorker是消费者,不断的从workQueue中获取新的任务。

    7 corePoolSize、maximumPoolSize和workQueue的关系

    新加一个任务的时候,如果线程池中的线程数小于corePoolSize的话,直接添加新的线程,如果大于等于corePoolSize,先试图将新的任务放入workQueue中,如果放不下的话,就新建一个线程,但是总的线程数不能超过maximumPoolSize。如果线程数已经超过了maximumPoolSize,那么reject处理这个任务,将这个任务交给RejectedExecutionHandler去处理。

    核心线程是最基本的worker,如果处理不过来就将任务放入任务队列中,这是第一道防止任务丢失的屏障。但是核心线程处理任务队列中的任务有一定的速度,加入任务来得太快的话,它就应付不过来了,会导致任务队列满了,再也放不下新的任务了,这个时候,就说明核心线程的处理能力不够,就会添加新的线程来帮助核心线程,这是第二道屏障。但是如果还是处理不过来的话,就只能够丢掉了。这个任务就交给RejectedExecutionHandler去处理。

    比如ThreadPoolExecutor的DiscardOldestPolicy这个策略,它把workQueue中最老的任务丢掉,然后把这个最新的任务投入执行。

    20 参考资料

    20.1 https://juejin.im/entry/58fada5d570c350058d3aaad

    20.2 https://www.cnblogs.com/dolphin0520/p/3932921.html

  • 相关阅读:
    rsync
    zabbix一键部署
    MYSQL高可用——MHA(概述与安装)
    正向代理的简单概括和应用
    kvm的简介与安装桥接
    linux下常用的五个查找命令
    简述MVC框架模式以及在你(Android)项目中的应用
    ThreadLocal源码分析
    Handler、Looper、MessageQueue、Thread源码分析
    HashMap总结
  • 原文地址:https://www.cnblogs.com/hustdc/p/10916557.html
Copyright © 2020-2023  润新知