0
点赞
收藏
分享

微信扫一扫

浅析java线程池

小沙坨 2022-03-12 阅读 83

浅析java线程池

Java线程池

1. 常见的四大线程池

  • Executors.newSingleThreadExecutor();
  • Executors.newFixedThreadPool();
  • Executors.newScheduledThreadPool();
  • Executors.newCachedThreadPool();

2. ThreadPoolExecutor的七大参数

  • Int corePoolSize
    • 核心线程数
  • int maximumPoolSize
    • 最大线程数(线程池中,最多存在多少个线程)
  • long keepAliveTime
    • 保持活跃的时间(在指定时间内,如果没有任务,释放非核心线程)
  • TimeUnit unit
    • 时间单位(参数TimeUnit中的常量)
  • BlockingQueue<Runnable> workQueue
    • 等待队列
  • ThreadFactory threadFactory
    • 创建线程的工厂
  • RejectedExectuionHandler handler
    • 拒绝策略

3. java四大线池程本质

  • java线程池本质上只有一个。
  • 无论哪个线程池,都是调用ThreadPoolExecutor创建出来的。
  • 线程池有不同的特性,是因为创建线程池的时候,参数不一样。

3.1 Executors.newSingleThreadExecutor简单线程池

​ 调用ThreadPoolExecutor构造函数时的七个参数值。

参数含义参数名称参数类型取值备注
核心线程corePoolSizeint1核心线程数为有且只有一个
最大线程maxNumPoolSizeint1最大线程数量只能存在一个
存活时间keepAliveTimelong0L线程保持活跃时间长度,加上时间单位计时
时间单位unitTimeUnitTimeUnit.MILLISECONDS参数TimeUnit中的常量
等待队列workQueueBlockingQueue<Runnable>LinkedBlockingQueue<Runnable>等待队列长度为Integer.MAX_VALUE(int最大值)

有且只有一个线程工作,队列无穷大,所有的任务,都交个这个线程来处理,不论任务多少,使用线程池中的唯一线程,依次的执行队列中的任务。

当核心线程数和最大线程数相等的时候,保持活跃的时间设置时没有意义的,应为核心线程不会被释放,最大线程数不会超过核心线程数,所以当任务执行完成之后,不会进行线程释放

等待队列 new LinkedBlockingQueue<Runnable>() 无界队列,构造方法中的初始长度为Integer.MAX_VALUE(int最大值)

等待队列无穷大,意味着该线程池时没有拒绝策略

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

3.2 Executors.newFixedThreadPool固定线程池

​ 调用ThreadPoolExecutor构造函数时的七个参数值,在创建这个线程池的时候,需要指定一个参数,该参数指定的是核心线程数和最大线程数

​ Executors.newFixedThreadPool(int size)

参数含义参数名称参数类型取值备注
核心线程corePoolSizeintsizesize由调用方法时,指定的数量决定
最大线程maxNumPoolSizeintsizesize由调用方法时,指定的数量决定
存活时间keepAliveTimelong0L线程保持活跃时间长度,加上时间单位计时
时间单位unitTimeUnitTimeUnit.MILLISECONDS参数TimeUnit中的常量
等待队列workQueueBlockingQueue<Runnable>LinkedBlockingQueue<Runnable>等待队列长度为Integer.MAX_VALUE(int最大值)

和newSingleThreadExecutor的区别在于,创建线程池时,需要指定一个数量size,size在其内部调用ThreadPoolExecutor构造方法时,作为核心线程数和最大线程数[同样导致活跃时间无效],等待队列也是无穷大

Executors.newFixedThreadPool和newSingleThreadExecutor的唯一区别就是需要指定一个线程数量

3.3 Executors.newScheduledThreadPool 安排

​ 调用ThreadPoolExecutor构造函数时的七个参数值,在创建这个线程池的时候,需要指定一个参数,该参数指定的是核心线程数

​ Executors.newScheduledThreadPool(int corePoolSize)

参数含义参数名称参数类型取值备注
核心线程corePoolSizeintsizesize由调用方法时,指定的数量决定
最大线程maxNumPoolSizeintInteger.MAX_VALUE等于无穷大
存活时间keepAliveTimelong0L线程保持活跃时间长度,加上时间单位计时
时间单位unitTimeUnitNANOSECONDS参数TimeUnit中的常量
等待队列workQueueBlockingQueue<Runnable>new DelayedWorkQueue()该队列的作用:队列中有等待任务,直接创建新线程

当前线程池,只指定一个初始化的核心线程数,等待队列相当于没有缓存机制,进入队列的任务会立刻创建新的线程来执行任务,由于线程保持存活的时间为0所以,超过核心线程数的线程在执行完任务后,会被释放

当达到核心线程数满了以后,就会创建新的线程,当新开出的线程,在完成任务之后,就会被直接销毁。当前线程池在理论上可以创建无穷个线程

DelayedWorkQueue 队列初始化的时候,长度为0,队列不缓存任务,入队列即刻出队列

3.4 Executors.newCachedThreadPool 缓存

​ 调用ThreadPoolExecutor构造函数时的七个参数值

​ Executors.newCachedThreadPool()

参数含义参数名称参数类型取值备注
核心线程corePoolSizeint0核心线程为0
最大线程maxNumPoolSizeintInteger.MAX_VALUE等于无穷大
存活时间keepAliveTimelong60L [一分钟]线程保持活跃时间长度,加上时间单位计时
时间单位unitTimeUnitTimeUnit.SECONDS参数TimeUnit中的常量
等待队列workQueueBlockingQueue<Runnable>SynchronousQueue<Runnable>该队列的作用:队列中有等待任务,直接创建新线程

当前线程池,没有核心线程数量,有任务的时候,启动线程,在线程任务完成之后,等待60秒,在此期间如果有新的任务,复用线程,如果没有新的任务,超过线程存活时间60秒,则销毁线程

4. 线程池的作用

​ 创建线程消耗的性能消耗比较大,将创建的线程存放起来,在线程执行后,不释放。线程的复用性提高,多任务的时候,其中一个线程执行完毕后,可以直接接受下一个任务,避免了创建线程的性能和时间消耗。

​ 不用每次执行任务的时候,都需要创建线程,线程可以复用的情况下,直接从线程池中获取线程,在线程完成任务后,不被释放,可以接受下一次任务。

​ 举例,一个银行平时只开三个窗口(核心线程数),某天业务量爆发,需要办理业务的人增多。三个窗口每个窗口每次只能帮一个人办理业务,很多人都只能在大厅等待(等待队列),如果大厅坐满了等待的人,银行会觉得需要办理业务的人太多了,于是会多开几个窗口,但不能大于银行本身的窗口最大数,当银行开启了足够多的窗口之后,大厅的人数开始减少。

​ 当大厅左右人都办理完业务离开两分钟之后(保持的活跃时间,时间单位),后开的那些窗口的任务完成了,就会将窗口关闭。

​ 另一种情况,线程池中的所有线程全部处在执行任务的状态。银行所有的窗口,都在处理业务,大厅的人没有减少,反而还在增加,这种情况下,银行需要告知后面来的人,需要换个时间再来办理,在线程池中是拒绝策略。

5. 自定义线程池

使用ThreadPoolExecutor自定义线程池。

线程池在刚创建出来的时候,里面是没有线程的。

在我们向线程池提交任务的时候,线程池才会开始创建线程。

如果核心线程数是10,最大的线程数是20,当我们提交第11个的时候(前十个没有结束),线程池会创建新的线程吗?

线程池创建线程的策略,先把核心线程数填满,然后填满等待队列,等待队列如果满了,就创建新的线程,但是总线程数不能大于最大线程数。

6. 线程池常见问题

  • 线程池刚创建的的时候,内部存在几个线程?
    • 线程池在刚创建的时候,内部没有线程
  • 线程池在创建之后,什么时候才会产生线程?
    • 在程序运行过程中,向线程池提交任务的时候,线程池才会创建线程
  • 如果核心线程数是10,最大线程数是20,当提交第11个任务是(前10个线程执行未结束),线程池会不会创建新的线程?
    • 不会,线程池创建线程的策略,先把核心线程数填满,然后填满等待队列,等待队列如果满了,就创建新的线程,总线程数不能大于最大线程数

核心线程永不销毁


拒绝策略后续继续补充…

做一个记录

举报

相关推荐

0 条评论