java 线程池介绍及使用 笔记

线程池

优点:

  1. 降低资源消耗(不用频繁创建/销毁线程)
  2. 提高响应速度(否则:线程创建时间–>运行时间–>销毁时间),只会花费运行时间,与数据库连接池道理一样
  3. 提高线程可管理性,统一分配调控监管

在这里插入图片描述
线程池的创建:

ExecutorService pool = new ThreadPoolExecutor(2,4,3,TimeUnit.SECONDS,
new ArrayBlockingList(10),new ThreadPoolExecutor.DiscardOldestPolicy());

1. 重要参数
corePoolSize 核心线程数()
maximumPoolSize 最大线程数
BlockingQueue 阻塞队列
keepAliveTime 空闲线程存活时间
RejectedExecutionHandler 拒绝策略,涉及到线程池工作机制
在这里插入图片描述
在这里插入图片描述

线程池工作简述

  1. 任务提交,创建新线程执行, 等线程数达到corePoolSize
  2. 将多余的任务放入阻塞队列
  3. 如果阻塞队列满了, 则继续创建新线程, 一直到达MaximumPoolSize
  4. 如果达到MaximumPoolSize后依然有任务提交,触发拒绝策略
    {1.丢弃阻塞队列中最靠前的任务,执行当前任务,
    2.直接抛异常(默认),
    3.由调用者线程来执行,
    4.直接丢弃当前任务,
    5.实现RejectExecutionHandler接口,自定义拒绝策略}
  5. 线程处理完任务,空闲keepAliveTime时间后,被回收
  6. 覆盖线程池的beforeExecute/afterExecute/terminated 方法,可以在任务执行前/执行后/线程池退出时做一些事情
  7. 提交无返回值的任务时, 使用execute方法,提交有返回值的任务时,请使用submit方法(提交callable),返回一个Future实现类结果,通过get()方法获得执行结果
  8. 关闭线程池:
    shutdown() : 遍历池内线程,并调用空闲线程的interrupt()方法
    shutdownNow() : 遍历所有池内线程,调用interrupt()方法,比较粗暴

2. 合理配置线程池

  1. 首先确认任务的特性,即提交给线程池的任务是什么类型的
    1. cpu密集型,最大线程数不要超过机器的CPU核心数+1,最大不要超过1,为什么要+1?防止页缺失(线程内容存到虚拟内存,再取出的过程,会花费IO时间,这时候CPU空出来,就可以执行这个多出来的线程)
      Runtime.getRuntime().availableProcessors();// 通过该方法获取机器可用CPU核心数
      
    2. IO密集型,公认的经验方法:可用cpu核心数*2,最佳情况需要监控一下操作系统用户态/核心态的时间,尽量降低核心态时间, 其线程数公式为:
      Nthreads = NCPUUCPU(1+W/C)
      NCPU:cpu逻辑核心数
      UCPU:期望的cpu利用率(0到1)
      W/C:是等待时间/计算时间的比率,这两个时间linux下使用vmstat或者top命令查看
    3. 混合型,尽量拆分成两个线程池单独配置,前提是io处理与cpu处理时间相差不太大,如果相差太大…没必要拆分了…哪个时间多按哪个配置
    4. 禁止在线程池中使用无界队列,任务量高峰时容易发生OOM

JDK预定义的线程池

1. Executors.newSingleThread(Scheduled)Executor(xxxxxx);单线程,任务顺序执行
2. Executors.newFixedThreadExecutor(xxxxx); 固定线程数的线程池
3. Executors.newCachedThreadPool();来任务就创建线程,执行完之后回收,弹性伸缩的线程数
4. Executors.newWorkStealingThreadPool(); 工作密取的线程池,是使用**ForkJoin**框架来实现的线程池
5. ExecutorService pool = Executors.newScheduledThreadPool(); 定时执行任务
  pool.scheduleWithFixedDelay();//间隔固定时间执行任务,该任务执行完,等待固定时间后,再重复执行
  pool.scheduleWithFixedRate();//间隔固定时间执行任务,任务执行开始计时,任务执行完毕停止计时,如果超过指定的时间,会马上重复执行该任务, 否则会等固定时间达成,才开始重复执行下一次
  //如果抛出异常,不会再重复执行,所以最好使用try/catch来包裹run方法中的内容

1到4在阿里不太推荐使用,最好还是使用基础的线程池创建方法,比较容易控制参数,实际使用见仁见智

ExecutorService pool = new ThreadPoolExecutor(2,4,3,TimeUnit.SECONDS,
new ArrayBlockingList(10),new ThreadPoolExecutor.DiscardOldestPolicy());

CompletionService接口包装的线程池:ExecutorCompletionService
获取有结果task返回值时更节省时间,其本质是线程池+结果阻塞队列
jdk1.8中新增了CompleteableFuture ,实现方式与这个相似
1.常规方式,线程在阻塞队列中, 只有前一个线程执行完,后一个线程才能执行并拿到结果
2.此种线程池,有个结果阻塞队列, 先执行完的任务把结果放到结果队列中,外部就可以获取到结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值