线程池相关以及扩展

2 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述

什么是线程池,为什么使用线程池,以及使用线程池的好处

线程池:是一种池化思想管理线程的工具。
Why: 线程过多会带来额外的开销,比如创建、销毁、调度的开销。也降低了机器的性能。
Good: 1、降低资源消耗:可以重复利用已创建的线程,避免线程创建销带来的开销
      2、提高响应速度:如果线程池中有空闲的线程可以直接拿来用
      3、提高线程管理性:对线程进行统一分配、管理、监控,防止线程的不合理分配
      4、扩展性:线程池可以实现线程的定时执行、延期执行

一、 线程池的工作原理,几个重要参数

  1. 判断workerCount < corePoolSize , 创建并启动新线程执行任务。
  2. 线程池是running状态 并且wokerCount >= corePoolSize 则加入阻塞队列中
  3. wokerCount >= corePoolSize 并且 workerCount <= maximumPoolSize 并且阻塞队列已满 并且状态位running 或许 为(shutdown and firstTask == null ) firstTask = null只有在runWoker时候,创建并启动新线程去执行任务。
  4. workerCount > maximumPoolSize 并且阻塞队列已满,执行拒绝策略,抛异常。
    1、corePoolSize 表示核心线程池的大小
    2、maximumPoolSize 表示线程池最大值
    3、keepAliveTime 表示存活时间,当线程池中线程数超过corePoolSize时候,并且线程空闲时间超过keepAliveTime 就会将这些线程销毁
    4、unit 存活时间单位
    5、workQueue 用于保存任务的阻塞队列
    6、threadFactory 创建线程的工程类 可以用来指定线程名前缀、优先级、异常处理等
    7、handler 用来处理阻塞队列饱和情况。有AbortPolicy 直接拒绝并抛RejectException  CallerRunsPolicy只用调用者所在线程去执行 DiscardPolicy 直接丢弃 DiscardOldestPolicy 丢弃队列中最久的任务,并执行
    

二、线程池有几种?每种什么特征,什么场景下会使用

 1、newCachedThreadPool corePoolSize=0,maximumPoolSize为Integer.MAX_VALUE,keepAliveTime 为60,unit 为SECONDS, workQueue 为同步队列 SynchronousQueue。
特点:新任务过来,会先去线程池中看有没有缓存的线程,如果有直接用,如果没有再创建。
适用:短期异步程序或者负载较轻
2. newFixedThreadPool corePoolSize\maximumPoolSize 接受自定义,keepAliveTime=0(不限时)unit为MILLISECONDS,workQueue为LinkedBlockingQueue无界阻塞队列
特点:线程池大小固定,线程存活时间无限,阻塞队列无限
适用:执行长期的任务
3. newSingleThreadExecutor corePoolSize\maximumPoolSize为1,keepAliveTime=0(不限时)unit为MILLISECONDS,workQueue为无界阻塞队列
特点:如果线程遇到错误中止,新的线程会代替它执行后续线程,还可以保证顺序执行,newFixedThreadPool(1)不同的是,newFixedThreadPool(1)如果线程遇到错误中止,无法使用替代线程。
适用:一个任务执行的场景
4. newScheduleThreadPool corePoolSize接受自定义,maximumPoolSize为Integer.Max_VALUE,keepAliveTime=0 不限时,unit为NANOSECONDS,workQueue为 DelayedWorkQueue()一个按照超市时间升序排序的队列。
床创建一个固定大小的线程池,线程存活时间无限制,线程池可以支持定时以及周期性任务执行,如果线程都处于繁忙状态则会进去DelayedWorkQueue队列中。
适用:周期性执行任务的场景
5. newSingleThreadScheduledExecutor corePoolSize 为1 的ScheduleThreadPool,支持线程如果遇到错误中止,新的线程会替代它执行后续线程。
6. newWorkStealingPool Fork/Join 线程池维护足够的线程支持给定的并行度级别,并可以使用多个队列来减少争用,工作窃取不保证提交任务的顺序性。

三、线程池的阻塞队列有几种,每种有什么特征,什么场景下使用

Queue接口
|———— BlockingQueue接口
|———— ArrayBlockingQueue类
|———— DelayQueue类
|———— LinkedBlockingQueue类
|———— PriorityBlockingQueue类
|———— SynchronousQueue类
操作类型	抛出异常	 	返回特殊值	阻塞线程		超时
插入	add(e)		offer(e)	put(e)		offer(e, time, unit)(无界队列不会超时)
删除	remove(e)	poll(e)		take(e)		poll(e, time, unit)(无界队列不会超时)
读取	element(e)(元素)	peek(e)(偷看)	/ 		/
1. ArrayBlockingQueue 有界的阻塞队列 内部实现是数组 采用先进先出的方式存储数据 最新数据插入到对象尾部 最新移出是头部数据
2. LinkedBlockingQueue 阻塞队列大小可配置,默认无界也就是Integer最大值 2的31次方 -1 内部实现是链表 也是采用先进先出方式存储数据,最新数据插入到对象尾部,最新移出是头部数据
3. PriorityBlockingQueue(源码分析) 阻塞队列是个无界队列,队列大小默认是11,可以自动扩容(//oldGap<64则扩容新增oldcap+2,否者扩容50%,并且最大为MAX_ARRAY_SIZE)siftUpComparable比较方法
4. SynchronousQueue 内部只允许存一个元素

四、线程池源码中运行状态和线程数是怎么存储的

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
    private static int workerCountOf(int c)  { return c & COUNT_MASK; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }

RUNNING 位移29后高三位为111

SHUTDOWN 位移29后高三位为000

STOP 位移29后高三位为001

TIDYING 位移29后高三位为010

TERMINATED 位移29后高三位为011

后29为为线程池数量

五、ThreadPoolExecutor源码分析

六、ThreadPoolTaskExecutor

七、正负数二进制

八、位运算

运算符		解释
&		只有两个对应位都为 1 时才为 1
|		只要两个对应位中有一个 1 时就为 1
^		只有两个对应位不同时才为 1

~ 		取反
原码:将一个整数转成二进制 就是原码 单字节的5的原码为:0000 0101;-5的原码为1000 0101
反码:正数的反码是其原码,负数的反码是将原码除符号位外每一位取反
补码:正数的补码就是原码,负数的反码 + 1就是补码
所以 ~5 过程为 正数的原码进行取反后得到补码,原码= 反码(补码- 1) 的取反
00000101 -> 11111010 -> 11111001 -> 10000110(-6)
同理 ~-5 过程为  负数 的补码取反 原码:10000101 -> 反码:11111010 -> 补码:11111011 -> 取反:00000100(4)
总结:~x = -x-1

九、举例说明工作中用到的线程池情况

十、execute 方法和submit方法

execute 方法只接受 Runnable
submit 可以接受Runnable也可以接受Callable

Runnable 和 Callable区别

1、Callable中方法为call,Runnable方法为run
2、Callable 可以抛异常,Runnable不可以
3、Callable 有返回值,Runnable 是void

十一、Runnable和Thread

可以理解为Runnable就是一个任务,Thread也实现了Runnable, 任务交给Thread去执行。资源共享没有意义,一个任务被多个线程启动,跑的还是这一个任务,没有意义。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值