如何理解线程池中的参数设计
- 你的线程池的参数怎么配置?线程数量设置多少合理?
- 如何确定一个线程池中的人物已经完成了
- 为什么不建议使用java自带的Executors创建线程池
- 线程池里面的阻塞队列设置多少合理?
考察:了解你对技术的掌握程度,|对于技术的理解、场景问题
线程池的参数有哪些
- 核心线程数
常驻在线程池中的工作线程数量 - 最大线程数
表示线程池中最大能容纳的线程数量(扩容) - 阻塞队列
当核心线程跑满的时候,存储任务的容器 - 等待时间
- 等待时间单位
- 拒接策略
超过线程池能够处理的容量的时候的保护机制 - 线程工厂
线程池的设计
池化技术->实现了对线程的复用(一个技术的产生背景)
- 线程数量不可控
- 线程的频繁创建和销毁带来的开销
ThreadPoolExector(Java实现)
通过生产者-消费者模型来解决线程服用问题(技术方案)
可以把基于阻塞队列的生产者消费者模型放大一下,就是分布式消息队列。
public class ThreadPoolDemo {
static Queue<Runnable> tasks = new LinkedList<>();
static class WorkThread implements Runnable {
@Override
public void run() {
while (true) {
Runnable task = tasks.poll();
if (task != null) {
System.out.println("工作线程开始执行:" + Thread.currentThread().getName());
task.run();
}else {
System.out.println("当前没有任务执行:" + Thread.currentThread().getName());
synchronized (WorkThread.class){
try {
WorkThread.class.wait();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) {
WorkThread workThread = new WorkThread();
new Thread(workThread).start();
Scanner scanner = new Scanner(System.in);
while (true){
String s = scanner.nextLine();
tasks.add(()->{
System.out.println(Thread.currentThread().getName()+"数据定时同步的任务,开始执行" + s);
}) ;
synchronized (WorkThread.class){
WorkThread.class.notify();
}
}
}
}
线程池的价值是什么?
架构思维
java开发,就真的只要会CRUD
职业发展-》架构,技术经理
- 生产者消费模型(支付,第三方支付,异步发送到第三方支付)
- 扩容和缩容的思想,工作线程的创建和销毁
- 阻塞队列
- 保护策略(拒绝策略),考虑系统的稳定性
Synchronized的锁升级
无锁-》偏向锁-〉轻量级锁-》重量级锁。
- 什么是偏向锁,什么是轻量级锁,什么是重量级锁。
- 为什么要设计锁升级?
- Synchronized是提供了锁的公平性吗?
- Synchronized锁标记怎么存储的?
- 重量级锁为什么称为重量级锁?
java5之前,是没有锁升级这个概念的
无锁-》重量级锁
加锁会带来性能开销:
- 内核指令的调用,涉及到上下文切换
- 线程阻塞唤醒,涉及到上下文切换‘
消耗cpu资源,影响程序的执行性能!
加锁的方式从并行变成了串行。
两个层面的优化
使用层面的优化
控制加锁的位置,也就是锁的范围。
JVM层面的优化
1,编译器的优化,深度编译(锁的膨胀和锁的消除)
2,锁的升级
思考:能不能在让线程阻塞之前,就竞争到锁呢?
轻量级锁(自旋锁)
自旋竞争锁,通过循环尝试获取锁来竞争到锁资源。平衡循环次数
前提是:通过自旋尝试获得锁的代价,要比线程进入到阻塞代价更低
价值
提炼出有价值的架构思维
如何平衡好性能和安全性之间的关系
库存,防止超卖和少卖
ConcurrenthashMap 1.7的版本锁的是Segment,1.8版本锁的是Node节点
Mysql,表锁,行锁,间隙锁,临键锁,MVCC乐观锁