18-并发容器应用之线程池

一、前言

我们知道了只个并发容器之后,那么看我们线程池 也是基于并发容器实现的
为什么要有线程池:
1、避免线程频繁的创建和销毁,浪费资源
2、提高响应速度,需要获取线程的直接去线程池中获取,不用创建,也节约了需要销毁线程时间
3、便于统一管理:线程可以放到线程池里面统一管理

二、实现线程池的几个要点

1、需要提前创建好,并可以保持
2、可以向线程池提交任务,并有执行任务的能务
3、可以接收来不及运行的任务
4、可以销毁

三、 jdk中线程池和工作机制

1、线程创建

ThreadPoolExecutor,jdk所有线程池实现的父类

2、ThreadPoolExecutor构造参数

coresize:线程池中核心线程数,小于coreSize就会创建新线程,等于coreSize就是将线程放到阻塞队列中,只有调用prestartAllCoreThreads()方法,才会一次性启动coreSize个线程
maxPoolSize:允许的最大线程数,阻塞队列也满了,< maxPollSize时,会创建新线程执行
keepAliveTime:线程空闲下来后,存活的时间,只有线程池线程个数》 coresize才有用
TimeUnit unit, 存活时间的单位值
BlockingQueue workQueue, 保存任务的阻塞队列
ThreadFactory threadFactory, 创建线程的工厂,给新建的线程赋予名字
RejectedExecutionHandler handler :饱和策略,有如下几种:

AbortPolicy :直接抛出异常,默认;
CallerRunsPolicy:用调用者所在的线程来执行任务
DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务
DiscardPolicy :当前任务直接丢弃
实现自己的饱和策略,实现RejectedExecutionHandler接口即可
实际应用中,如果线程过多,不可能将任务丢弃,那么我们需要实现自己的饱和策略,如果写入数据库,后面再通过定时 将丢弃的任务重新执行,或者推送到消息中间件 去消费,或打日志等。

3、提交任务

execute(Runnable command) 不需要返回
Future submit(Callable task) 需要返回

4、关闭线程池

shutdown(),shutdownNow();
shutdownNow():设置线程池的状态,还会尝试停止正在运行或者暂停任务的线程
shutdown()设置线程池的状态,只会中断所有没有执行任务的线程

5、工作机制

线程池在初始化的并不会创建线程池,在提交任务的时候才会创建线程

public void execute(Runnable command) {
     if (command == null)
         throw new NullPointerException();
     int c = ctl.get();
     if (workerCountOf(c) < corePoolSize) {//线程数小于核心线程数
         if (addWorker(command, true))//新创建线程执行任务
             return;
         c = ctl.get();
     }
     if (isRunning(c) && workQueue.offer(command)) {//大于核心线程数那么加入阻塞队列
         int recheck = ctl.get();
         if (! isRunning(recheck) && remove(command))
             reject(command);
         else if (workerCountOf(recheck) == 0)
             addWorker(null, false);
     }
     else if (!addWorker(command, false))//加入队列失败《 maxsize,进行新线程执行
         reject(command); //拒绝新任务
 }

在这里插入图片描述

所以线程执行顺序
在这里插入图片描述
在这里插入图片描述

3、常用线程池

FixedThreadPool
创建固定线程数量的,适用于负载较重的服务器,使用了无界队列
SingleThreadExecutor
创建单个线程,需要顺序保证执行任务,不会有多个线程活动,使用了无界队列
CachedThreadPool
会根据需要来创建新线程的,执行很多短期异步任务的程序,使用了SynchronousQueue
WorkStealingPool(JDK7以后)
基于ForkJoinPool实现
ScheduledThreadPoolExecutor
需要定期执行周期任务,Timer不建议使用了。
newSingleThreadScheduledExecutor:只包含一个线程,只需要单个线程执行周期任务,保证顺序的执行各个任务
newScheduledThreadPool 可以包含多个线程的,线程执行周期任务,适度控制后台线程数量的时候
方法说明:
schedule:只执行一次,任务还可以延时执行
scheduleAtFixedRate:提交固定时间间隔的任务
scheduleWithFixedDelay:提交固定延时间隔执行的任务
两者的区别:

scheduleAtFixedRate任务超时:
规定60s执行一次,有任务执行了80S,下个任务马上开始执行
第一个任务 时长 80s,第二个任务20s,第三个任务 50s
第一个任务第0秒开始,第80S结束;
第二个任务第80s开始,在第100秒结束;
第三个任务第120s秒开始,170秒结束
第四个任务从180s开始
参加代码:ScheduleWorkerTime类,执行效果如图

4、Executor框架

了解CompletionService
执行线程的任务有多个,需要得到结果,那么这个结果需要存下来,需要取的时候能取到

将结果放入到容器中存储,1先放 2 先放
自己实现:只能也是只能按顺序拿结果 只能先拿1 再拿2 这有问题

通过CompletionService
去线程池中拿任务
先完成的任务要,可以通过CompletionService先拿到

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值