并发编程
2025-10-27 19:52:17 0 举报
AI智能生成
并发编程学习
作者其他创作
大纲/内容
并发编程
并发 并行 串行
并发
两个以上同时发生
抢着做一件事
一个车道
高并发
达到系统承受能力的极限
并行
两个以上的人同时给你做事情
5个车道
串行
排着做
如何提供并发能力
1.sql优化 缓存 接口设计
2. 内存 磁盘 网卡 cpu 带宽
3. CPU 多核 超核
多线程
线程
创建
Thread
Runnable
Callable/FetureTask
new FutureTask(Callable)
new Thread(task)
task.get
线程池
生命周期
new
创建 未调用start
runnable
调用start
blocked
sync lock
被动等待 只能阻塞
waiting
wait join park
等待其他人
time_waiting
有时间的等待
sleep
park
join
interupted
任务结束终止
强行关闭
stop
不推荐使用
interrupt
中断信号线程自己决定关闭
Thread.currentThread.isInterrupted()
isInterrupted
中断标记的状态
interrupted
获取终端标记复位
join
底层是wait
锁
synchronized
并行改串行
会有标记 对象头
锁范围
类锁
对象锁
锁升级
why 提升性能
阻塞唤醒耗性能
流程
偏向锁
偏向某个线程
对象头记录锁的信息 线程id
轻量级锁
自旋 + CAS
有没有释放锁 释放了拿到锁
乐观锁 不阻塞线程
重量级锁
CAS
compareAndSwap
判断有没有被人改过
配合自旋使用
ABA问题
加个版本号
RentrantLock
并行改串行
原理
UnFair
Init Try ACQUIRE
CAS改volatile state
成功
标记获取锁的线程
失败
state == 0
获取锁
state != 0 且是当前线程
重入 + 1
获取锁成功
Try ACQUIRE
CAS
addWaiter Node(Thread)
CAS 加入新节点
Acquire Queued
如果前面一个节点是head
自旋CAS尝试获取锁
LockSupport.park
unlock
tryrelease
修改state状态
重入锁-1
线程改为null
waistatus 是否异常
异常从尾部遍历找正常的节点
并发情况下先设置的是pre节点 next节点可能没设置 所以是反向遍历
unpark head后一个节点
head基本为虚拟节点
公平锁unlock 必须在队列
Sync RentrantLock
JDK 底层 api
Sync 异常释放锁
lock能响应中断 Sync不会
lock可以公平锁
都是可重入锁
1.6Sync性能差 后面有了锁升级
lock可以手动释放 设置超时
lock可以有多个等待队列
乐观锁
不阻塞其他线程
悲观锁
阻塞其他线程
并发
原子性
当前操作的时候不允许有其他人进行操作
经典案例 i++
可见性
线程改的变量 其他线程得可见
有序性
在多线程的时候代码的执行顺序会发生变更
单线程不会
可见性有序性产生原因
CPU
L1
L2
L3
HZ总线频率
缓存性能提升
缓存一致性问题
总线锁
MESI
M
主线缓存不一致 只缓存再当前CPU
E
数据只在当前CPU没有被修改
S
数据缓在多个CPU且没有被修改
I
数据在当前CPU无效
多CPU异步操作导致的
StoreBuffer
更改操作
Invalidate queue
是其他CPU缓存无效化
volatile
HappensBefore
程序顺序性规则
锁定原则
volatile
Thread.start
Thread.join
Thread.inturrept
传递性原则
ThreadLocal
每个线程都有自己的副本
源码
Thread找到T和TheadLocal Map
get
when null
initValue
createMap
new ThreadLocalMap(key, value)
数组 size16
& 计算获取下标值
是否hash冲突(线性探测法)
不冲突 数组 item 放入 Entry
key为thread local对象的hashcode.
key为弱引用 value强引用
如果Threadlocal对象引用 希望对象可以回收
冲突 放入后一个节点
设置扩容因子 2/3
set
threadlocal的key获取下标
是否hash冲突
否
直接存
是
找key相等存入 或者 数组item == null的时候直接存
key为null
向前向后将key=null的替换成null
下一次遍历找i
面试题
1. 为什么key要用弱引用
当threadlocal引用断开时希望可以回收
2. 为什么value不用强引用
key存在value为nul不合理
3. Threadlocal如何实现线程隔离
每个线程一个ThreadLocalMap
线程获取ThreadLocalMap
16长度的的数组
不同的Threadlocal 存在不同的下标位置
4. ThreadLocalMap如何防止内存泄漏
ThreadLocal对象在Entry中是弱引用
ThreadLocal有完善的机制回收key == null的对象
使用的时候remove
5. 怎么解决hash冲突
hashcode有魔术 尽可能保证不冲突
线性探测 找到下一个为null的节点
6. 扩容
2倍扩容
原来的值rehash存储
HashMap
new HashMap
大小
2的幂次方
hash与计算的时候 决定因素为 hashcode 而不是数组长度
扩容因子
put
key hash
hashcode 高低16位异或运算
降低hash冲突 扰动函数
resize()
初始化node的数组
新建一个长度2倍的数组
rehash挪数据
hash 冲突
链地址
生成链表
长度超过8 数组长度大于等于64 转为红黑树
红黑树长度小于等于6转为链表
面试题
1. hashmap如何扩容的
1. 构造方法可传初始容量和扩容因子, 初始容量会初始化为2的倍数
2. 如果没有设置就是16, 扩容因子为0.75
3. 申请一个双倍容量的数组, 迁移数据
2. hashmap是如何解决冲突的
1. hashcode 低 16 位 与高16位异或运算
2. 如果冲突会通过链地址法解决冲突
3. 如果链表长度大于8 数组长度小于64 会触发扩容 数组长度大于64会转为红黑树
4. 红黑树长度小于6会转化为链表
3. 并发的时候会产生什么问题
覆盖
数据丢失
报错
链表或者冲突
CHM
put
数组节点为空
CAS
数组有值
synchronized
线程池
使用固定的线程数 来执行不定的Task
ThreadPoolExecutor
核心参数
核心线程数
最大线程数
最大空闲时间
时间单位
队列
线程工厂
拒绝策略
流程
构造方法
execute
小于核心线程
核心线程执行
大于核心线程 进阻塞队列
核心线程也会消费
阻塞队列满了
由工作线程执行 不超过最大线程
最大线程满了 执行拒绝策略
面试题
1 核心线程和最大线程会被回收吗
只有核心线程数和最大线程数的说法, 回收上没有区别的
timed maxThread > core num or 允许核心线程回收
0 条评论
下一页