内核态/用户态
CPU的执行级别切换,0,1,2,3
0 内核级别
1
2 用户级别
3
上下文切换:
1.进程与进程切换
2.进程内部内核态与用户态切换
3.线程与线程切换
4.线程与外部进程的线程切换
OS级别的锁
1.互斥锁 pthread_mutex,如果拿不到锁则睡眠,进入内核态,因为发生了一次系统调用
2.自旋锁 pthread_spin_t ,即spinLock,如果拿不到锁,一直死循环空转,OS内部处理
3.信号量
CAS(Compare and Swap)简述
原子操作:对于一堆操作,要么全部完成,要么全部失败,例如:事务
乐观锁思想的一个体现,无锁编程
CAS 本质是自旋(死循环),比较旧值是否为期望的值, 如果是,则更新为新值, 如果不是,则重新取旧值作为期望值,重新计算,然后再比较旧值与期望值是否相同…如此反复,直到旧值与期望值相同
使用现代CPU都支持的 CAS:cmpxchg指令(内存地址, 旧值,新值) 来保证CAS的可靠性,耗时大约0.6ns(纳秒)一次
JDK中大量实现CAS机制
例:ConcurrentHashMap , 在1.8以前用的悲观锁/显式锁,1.8后使用CAS
CAS的问题:
-
ABA问题,说明:有一个变量值为A, 线程1与线程2同时来修改A, 线程1比较快速, 把A改成C,又改回了A, 这个时候线程2也在改,A改成B , 这个时候线程2是发现不了这个变量曾经变成了C,又变回到A. 如何解决:在变量上加修改版本号, CAS时除了比较值外,还要比较版本号
-
时间开销问题:CAS是个纯计算性的问题, 如果长时间未成功, 会占用较长时间
-
只能保证一个共享变量的原子操作:因为cpu的cas指令只能针对一个内存地址,所以每次只能处理一个地址的变量 如何解决:将多个变量合并为一个类,使用JDK的原子操作类: AtomicXXXXX
用于解决ABA问题的类
AtomicMarkableReference 只会标记旧值是否有修改
AtomicStampedReference 会记录旧值被修改了多少次(版本号)