研发人员的一些常用的关键知识总结,做后端开发的,JAVA、数据库、Redis应该是最常用的了;
volatile
可见性
问题?
CPU1和CPU2上都有线程去操作该变量,读取会优先CPU内cache值
每次修改变量都会同步到主内存
每次读取强制从主内存读取,而非CPU cache内
禁止指令重排序
https://tech.meituan.com/2014/09/23/java-memory-reordering.html
多线程共享变量原子性问题无法解决
i++等操作
字节码指令三步操作
读取
+1
赋值回去
非原子操作
其它解决方案?
原子操作类AtomicInteger
CAS操作
底层原理
CAS
自旋
锁机制
ReentrantLock
源码解读?
synchronized
monitorenter
monitorexit
获取监视器对象monitor的持有权
ThreadLocal
线程局部变量
内存泄露问题
ThreadLocalMap中Key为弱引用,value为强引用
GC时value不会清理
手动remove
线程池
execute和submit区别
execute提交不需要返回值的任务
无法判断任务是否被线程池执行成功
submit提交需要返回值的任务
通过Future获取结果
ThreadPoolExecutor
corePoolSize
核心线程数,最小可以同时运行的线程数量
maximumPoolSize
当队列中存放的任务达到队列容量时,当前可以同时运行的线程数量为最大线程数
workQueue
新任务提交时,判断当前运行的线程数量是否达到核心线程数,达到的话新任务存入队列
keepAliveTime
线程池线程数大于核心线程数,此时没有新任务提交,多余线程等待时间后销毁
unit
时间单位
threadFactory
线程工厂,创建线程使用,指定线程名
handler
饱和策略
运行线程达到最大线程数量且队列已满
AbortPolicy
抛出 RejectedExecutionException来拒绝新任务的处理
CallerRunsPolicy
调用执行自己的线程运行任务,调用execute的线程来执行任务
DiscardPolicy
不处理新任务,直接丢弃掉
DiscardOldestPolicy
丢弃最早的未处理的任务请求
原子操作
AtomicInteger
CAS+volatile+native保证原子操作
避免synchronized的高开销,OS级锁,有用户态内核态交换
AtomicLong
……
AQS
构建锁和同步器的框架
组件
CountDownLatch
控制多线程间同步等待
Semaphore
允许多个线程同时访问
CylicBarrier
类似CDL
乐观锁悲观锁
悲观锁
每次读数据都认为会被修改,都要上锁
读上锁阻塞
sync RL都是悲观锁
乐观锁
每次读取都认为不会被修改,不会上锁
更新时会通过版本号或者CAS算法判断
CAS引出ABA问题
增加对象引用判断
当前对象引用是否等于预期引用
CAS自旋问题
长时间不成功造成CPU开销较大
AtomicXXX就是乐观锁
数据库
InnoDB
行级锁
锁算法
Record Lock
单行记录上的锁
Gap Lock
间隙锁,锁定一个范围,不包括记录本身
Next-key Lock
以上两种结合,锁定范围包含记录本身
MyISAM
表级锁
大表优化
限定查询范围
禁止不带任何条件的查询语句
读写分离
主写
从读
分库分表
垂直拆分
一张表列拆开到多张表中
水平拆分
按记录数拆分
B树
所有节点有key和data
叶子节点独立
B+树
只有叶子有key和data
叶子节点有指针关联
redis
如何判断数据过期
过期字典保存数据过期时间
惰性删除
取出key时过期检查
定期删除
定期抽取一部分key,执行删除过期key操作
缓存穿透
请求落到数据库上,缓存没有
解决
缓存无效key
布隆过滤器
缓存雪崩
同一时间,大面积缓存失效
解决
随机缓存时间
redis集群