一文读懂 Java-线程池

Java-线程池

概念

  • 创建线程要花费昂贵的资源和时间,如果任务来了才创建那么响应时间就会变成,而且一个进程创建的线程数有限
  • 线程池就是首先创建一些线程,它们的集合成为线程池,线程池在系统启动时即创建大量空闲线程,程序将一个任务传给线程池,线程池就会启动一条线程执行这个任务,执行结束后,线程并不会死亡,而是再次返回线程池中成为空闲状态

优势

  • 降低资源消耗,通过重复利用已创建的线程降低创建和销毁的花费
  • 提高响应速度,任务可以不需要等到线程创建就能立即执行
  • 提高线程可管理性,使用线程池可以统一分配,调优和监控

创建

new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);
  • corePoolSize: 线程池基本大小,当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时,(除了利用提交新任务来创建和启动线程(按需构造),也可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。)
  • maximumPoolSize: 线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。对于无界队列,可忽略该参数。
  • keepAliveTime: 线程存活时间,当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。
  • runnableTaskQueue: 任务队列,用于传输和保存等待执行任务的阻塞队列
    • ArrayBlockingQueue: 基于数组结构的有界阻塞队列,FIFO先进先出排序
    • LinkedBlockingQueue: 基于链表结构的阻塞队列,FIFO排序,吞吐量高于ArrayBlockingQueue,静态工厂方法
    • SynchronousQueue: 不存储元素的阻塞队列,每个插入必须等到另一个进程调用移除操作,否则插入一直处于阻塞状态; 吞吐量高于LinkedBlockingQueue
    • PriorityBlockingQueue: 具有优先级的无界阻塞队列
  • threadFactory: 线程工厂,用于创建新线程,threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。
  • handler: 线程饱和策略,当任务太多来不及处理时,用于拒绝任务,实现了RejectedExecutionHandler接口
    • AbortPolicy: 直接抛出异常,阻止系统正常运行
    • CallerRunsPolicy: 直接在调用者线程中,运行当前被丢弃的任务
    • DiscardOlderPolicy: 丢弃最老的一个请求,并执行当前任务
    • DiscardPolicy: 丢弃无法处理的任务,不予任何处理

流程

avator

  • 首先判断基本线程池是否已满,未满则创建一个工作线程执行任务,满了则下一步
  • 线程池判断工作队列是否已满,未满则将新提交的任务存储到工作队列中,满了则下一步
  • 线程池判断整个线程池是否已满,未满则创建新的工作线程执行任务,满了则交给饱和策略处理

线程池提交

  • 使用execute提交,没有返回值
  • 使用submit提交,会返回一个future,通过future.get()获取,阻塞直到任务执行完,而get(long timeout,TimeUnit,unit)方法则会阻塞一段时间后立即返回
Future<Object> future = executor.submit(harReturnValuetask);
try{
    Object s = future.get();
}catch (InterruptedException e){
    //处理中断异常
}catch (ExecutionException e){
    //处理无法执行任务异常
}finally{
    //关闭线程池
    executo.shutdown();
}

线程池的关闭

  • 调用线程shutdown或shutdownNow方法,遍历线程池中的的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止
  • 区别在于: shutdownNow将线程池的状态设为STOP,然后尝试停止所有的正在执行或暂定任务的线程,并返回等待执行任务的列表; 而shutdown是将线程池的状态设为SHUTDOWN状态,然后中断所有没有正在执行任务的线程
  • 只要调用了两个方法中的任意一个,isShutdown方法就会返回true,而所有的任务都已关闭即所有的线程池关闭,isTerminated才会返回true

线程池的配置

  • 任务性质
    • CPU密集型任务: 尽量使用较小的线程池,核心数+1,若开过多的线程池,会造成CPU过度切换
    • IO密集型任务: 使用稍大的线程池,核心数*2,IO密集型CPU使用率不高,因此CPU在等待IO时有其它线程处理其它任务
    • 混合型任务: 可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理
  • 任务优先级: 高,中,低
  • 任务执行时间: 长,中,短
  • 任务依赖性: 是否依赖其他系统资源,如数据库连接

Java提供的线程池

  • newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)
  • newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)
  • newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务
  • newScheduledThreadPool:适用于执行延时或者周期性任务

线程池的监控

  • taskCount: 线程池需要执行的任务数量
  • completedTaskCount: 已完成的任务数量,小于等于taskCount
  • largestPoolSize: 曾经创建过的最大线程数量,可以判断线程池是否满过
  • getPoolSize: 线程池线程数量,若线程池不销毁的话,线程不会自动销毁
  • getActiveCount: 获取活动的线程数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值