线程池参数

1、为什么使用线程池(线程池好处)?

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务,如果提交的任务超过了线程能执行的最大数量,超出的数量的任务会被提交到一个阻塞队列排队等候,等其他线程执行完毕,再从队列中取出任务来执行.

主要特点为:线程复用、控制最大并发数、管理线程.

  1. 降低资源消耗。 通过重复利用已经创建的线程,降低线程创建的和销毁造成的消耗。例如,工作线程Woker会无线循环获取阻塞队列中的任务来执行。

  2. 提高响应速度。 当任务到达时,任务可以不需要等到线程创建就能立即执行
  3. 提高线程的可管理性。 线程是稀缺资源,Java的线程池可以对线程资源进行统一分配调优监控

2、线程池的工作流程?

一个新的任务到线程池时,线程池的处理流程如下:

  1. 判断核心线程池里的线程是否都在执行任务(即核心线程是否已满), 如果不是,创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务(即核心线程已满),则进入下个流程。
  2. 判断阻塞队列是否已满 如果阻塞队列没有满,则将新提交的任务存储在阻塞队列中。如果阻塞队列已满,则进入下个流程。
  3. 判断线程池里的线程是否都处于工作状态(即线程池是否已满) 如果没有,则创建一个新的工作线程来执行任务。如果已满,则交给饱和策略来处理这个任务。

   线程池工作流程图如下:

          

3、线程池实现类

线程池的核心实现类是ThreadPoolExecutor,用来执行提交的任务。因此,任务提交到线程池时,具体的处理流程是由ThreadPoolExecutor类execute()方法去完成的。

  1. 如果当前运行的线程少于corePoolSize,则创建新的工作线程来执行任务(执行这一步骤需要获取全局锁)。
  2. 如果当前运行的线程大于或等于corePoolSize,而且BlockingQueue未满,则将任务加入到BlockingQueue中。
  3. 如果BlockingQueue已满,而且当前运行的线程小于maximumPoolSize,则创建新的工作线程来执行任务(执行这一步骤需要获取全局锁)。
  4. 如果当前运行的线程大于或等于maximumPoolSize任务将被拒绝,并调用RejectExecutionHandler.rejectExecution()方法。即调用饱和策略对任务进行处理

工作线程(Worker): 线程池在创建线程时,会将线程封装成工作线程WokerWoker在执行完任务后,不是立即销毁而是循环获取阻塞队列里的任务来执行阻塞队列为空,就阻塞等待,直到阻塞队列中有任务。

     

4、线程池的创建(7个参数)

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

4.1、corePoolSize :核心线程池的基本大小

  1. 线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。
  2. 提交一个任务到线程池时,线程数小于corePoolSize,会创建一个新的线程来执行任务。注意: 即使有空闲的核心线程能执行该任务,也会创建新的线程
  3. 如果线程池中的线程数已经大于或等于corePoolSize,则不会创建新的线程。
  4. 如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程

4.2、maximumPoolSize(线程池的最大数量): 线程池允许创建的最大线程数。

  1. 如果使用无界的阻塞队列该参数没有什么效果
  2. 一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接执行,如果没有则会缓存到工作队列(后面会介绍)中,如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。

4.3、keepAliveTime(线程活动保持时间): 

  1. 多余的空闲线程的存活时间。如果任务多而且任务的执行时间比较短,可以调大keepAliveTime,提高线程的利用率。
  2. 当空闲时间达到keepAliveTime时,多余的线程将被销毁,直至只剩下corePoolSize的数量为止。

4.4、unit(线程活动保持时间的单位): 

  1. 可选单位有

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

4.5、workQueue(工作队列): 

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

  1. ArrayBlockingQueue 基于数组结构的有界阻塞队列,按FIFO(先进先出)原则对任务进行排序。使用该队列,线程池中能创建的最大线程数为maximumPoolSize
  2. LinkedBlockingQueue 基于链表结构的无界阻塞队列,按FIFO(先进先出)原则对任务进行排序,吞吐量高于ArrayBlockingQueue。使用该队列,线程池中能创建的最大线程数为corePoolSize静态工厂方法 Executors.newFixedThreadPool()使用了这个队列。
  3. SynchronousQueue 一个不存储元素的阻塞队列。添加任务的操作必须等到另一个线程的移除操作否则添加操作一直处于阻塞状态静态工厂方法 Executors.newCachedThreadPool()使用了这个队列。吞吐量通常要高于LinkedBlockingQuene;
  4. PriorityBlokingQueue 一个支持优先级无界阻塞队列。使用该队列,线程池中能创建的最大线程数为corePoolSize

4.6、threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。可自定义。

4.7、handler(饱和策略,或者又称拒绝策略): 

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的。

通过实现RejectedExecutionHandler接口可以自定义拒绝策略,但是拒绝策略是一种处理较为极端的情况的方式,正常情况下尽量通过合理的设计线程池来防止溢出。

jdk中提供了4中拒绝策略:

  • CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

       

  • AbortPolicy

       该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

       

  • DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

       

  • DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

       

5、线程池的种类

JAVA8中JDK有5种定义好的线程池,分别是:

  1. FixedThreadPool: 创建一个定长线程池,可控制线程的最大并发数,超出的线程会在队列中等待,newFixedThreadPool创建的线程池corePoolSize和MaxmumPoolSize是相等的,它使用的任务队列是LinkedBlockingQueue。
  2. SingleThreadPool:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务都按照指定顺序执行。newSingleThreadExecutor将corePoolSize和MaxmumPoolSize都设置为1,它使用的任务队列是LinkedBlockingQueue。
  3. CacheThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则创建新线程。newCachedThreadPool将corePoolSize设置为0,MaxmumPoolSize设置为Integer.MAX_VALUE,它使用的是SynchronousQUeue,也就是说来了任务就创建线程运行,如果线程空闲超过60秒,就销毁线程。
  4. ScheduledThreadPool:创建一个可以按时间周期执行任务的线程池,使用的任务队列是DelayedWorkQueue。
  5. WorkStealingPool:java8新增,使用目前机器上可以的处理器作为他的并行级别。

以上五种线程池都可以使用Executors来创建:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中线程池参数包括以下7个: 1. corePoolSize:线程池的基本大小,即在没有任务需要执行的时候线程池的大小。 2. maximumPoolSize:线程池最大的大小,即线程池中允许的最大线程数。 3. keepAliveTime线程池中的线程空闲后,保持存活的时间。 4. unit:keepAliveTime的时间单位。 5. workQueue:任务队列,用于保存等待执行的任务的阻塞队列。 6. threadFactory:线程工厂,用于创建新线程。 7. handler:拒绝策略,用于当任务队列已满,且线程池中的线程数达到maximumPoolSize时,如何拒绝新任务的策略。 下面是一个示例代码,展示了如何使用Java中的线程池参数: ```java import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { // 创建一个线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 4, // maximumPoolSize 60, // keepAliveTime TimeUnit.SECONDS, // unit new ArrayBlockingQueue<Runnable>(4), // workQueue Executors.defaultThreadFactory(), // threadFactory new ThreadPoolExecutor.AbortPolicy() // handler ); // 提交任务 for (int i = 0; i < 10; i++) { executor.execute(new Task(i)); } // 关闭线程池 executor.shutdown(); } static class Task implements Runnable { private int num; public Task(int num) { this.num = num; } @Override public void run() { System.out.println("正在执行task " + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task " + num + "执行完毕"); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值