Executors(线程池工具类)
不建议使用 ,主要是为了展现 ThreadPoolExecutor 不同参数,所展现的不同效果
以 外包 公司 接项目 为例子 , 一个员工只可以 干 一个 项目 ,
例子 就是 公司 接了100个项目
public class Test01 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService = Executors.newFixedThreadPool(10);
// executorService = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 100; i++) {
executorService.execute(new MyTask(i));
}
System.out.println("项目发放完毕");
}
}
class MyTask implements Runnable {
int name;
public MyTask(int i) {
name = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 接了 第"+name+" 项目");
int random = (int) (Math.random()*10000+1000);
// System.out.println(random);
SleepTools.ms(random);
}
}
-
newCachedThreadPool
- 这个 线程池 核心线程为 0 , 最大线程 为int的最大值(非常大),活跃时间为1个小时,阻塞队列为SynchronousQueue(同步)
- 当 这个 池接到了 100个项目 , 就会把第一个项目放到阻塞队列,发现没有核心员工,招聘一个,依次这样,就会招聘 100个 临时员工 , 工作的速度非常快
- SynchronousQueue(典型的 生产者 和 消费者),里面只能存一个元素
- 导致 第几个任务 会对应 招聘的第几个 员工
- 如果 假设 每一个 员工都是 大佬 ,解决项目的速度非常快,就会出现这样的现象
-
- 解释 : 假设当70 个项目 接到时 公司里已经有 员工 结束了手里的项目 那么就没必要 再招聘了
-
newFixedThreadPool
- 这个 线程池 核心线程为 所传的值, 最大线程 为所传的值,活跃时间 只对临时的有用,所以这个直接为0 阻塞队列 为 LinkedBlockingQueue
- 当 这个 池接到了 100个项目 ,就会全部交给 核心员工,因为最大的线程 和 核心线程相等,就会导致,无法招聘临时工,其他的项目只能,等,
- LinkedBlockingQueue无 界 队列 这队列 可以 存放 int MAX个元素 和无线大差不多
-
newSingleThreadExecutor
- 这个 线程池 核心线程为 1, 最大线程 1,活跃时间 只对临时的有用,所以这个直接为0,阻塞队列为LinkedBlockingQueue
- 当 这个 池接到了 100个项目 ,一个一个交给 这个核心员工,直接累死。速度也是非常慢
- 不推荐的原因
- 容易 OOM
- 而且 newFixedThreadPool 和 newSingleThreadExecutor还容易 内存 100%
- 原因 就是无界队列 ,队列存的数据 ,肯定占用内存 ,如果 无限次数的存 , 内存肯定 会炸
-
newCachedThreadPool 这个 导致 cpu 100 % , 因为来一个 就可以 处理一个 虽然 节省了内存 ,但是 cpu 压力巨大
-
不推荐 就是 阻塞队列 和 线程 的参数 不合适
-
如果 并发 根本就不高 ,而且 业务 也不是 很复杂 ,随便用,yyds
-
如果 高并发 业务杂 ,就需要 自定义 线程池
-
自定义也不难 就是 ThreadPoolExecutor 自己设置参数,权衡一下
-
new ThreadPoolExecutor(10, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20));
-
参数 解释 如果 当前来了60个任务 ,
-
20个任务会交给 10个核心 和 10个 非核心来处理
-
20个会交给 阻塞队列
-
还有 20 个 会 被拒绝(交给拒绝策略)
-
60分钟 10个非核心的就会被释放
-
-
ThreadPoolExecutor非常重要的一个类
-
构造参数 (以 外包 公司来解释,一个员工只可以做一个项目)
- corePoolSize(int) 核心线程数
- 相当于 外包公司的 核心员工 , 如果接到项目就可以直接做
- maximumPoolSize(int) 最大线程
- 相当于 外包公司 可以容纳的 最多员工, 如果项目一下子接了 100个 ,但是核心员工只有20个,但是最大线程 是 50 ,那么就会再去 招聘 30个临时的员工(非核心)
- keepAliveTime(long) 活跃时间
- 这个相当于 临时工的 合同 ,一旦到期 就 bye 了
- workQueue(BlockingQueue) 阻塞队列
-
threadFactory(ThreadFactory) 拒接策略
-
handler(RejectedExecutionHandler)
- corePoolSize(int) 核心线程数
Executor
- Executor 的 execute
-
ExecutorService 的 submit
-
AbstractExecutorService 对 submit 进行了 实现,里面调用 了 execute
- 区别
- execute 没有返回值
- submit 有返回值
ThreadPoolExecutor 源码 分析
原码,反码 ,补码
这三个只对 负数 有意义
正数 的 三码 一模一样
负数的 计算
以 8 位为例子
最高位 表示 符号 0为正数 1为负数
- 负数
- 原码
- 就是 转为 二进制 后 最高位变为 0
- 反码
- 就是 原码 是数字位 全部 0变1 1变0
- 补码
- 就是 反码 加1
数 | 原码 | 反码 | 补码 |
7 | 0000 0111 | 0000 0111 | 0000 0111 |
-7 | 1000 0111 | 1111 1000 | 1111 1001 |
计算
-
6 - 18 = 6 + (-18) = [0000 0000 0000 0110]补 + [1111 1111 1110 1110]补 = [1111 1111 1111 0100]补 = [1111 1111 1111 0011]反 = [1000 0000 0000 1100]原 = -12