最近想复习下java的一些知识,目前这块先把锁这块再看一下,这是今天看的一些东西,加上自己 的一些理解。不喜勿喷。
1.CAS
cas实现逻辑为调用unsafe的comparAndSwap来实现.通过比较和替换实现赋值操作,
在比较当前值(每次都会从主内存获取一次)是不是等于内存值,如果等于则把目标值设置为内存值
如果不等于就自旋知道改变为止。
hotstop底层实现是通过加了LOCK comxchg 指令来实现。
但是CAS存在ABA问题,在赋值时候,当前值可能被别的线程修改过两次
如: 1 — 2 ----1
可以通过加版本信息来保证或者加一个标识符。
2.锁升级过程
1.偏向锁
一个线程访问一个资源时候,则会在当前对象的markword添加锁标记为偏向锁,并且记录此线程标识
2.自旋锁,轻量级锁
当有两个或多个线程(单个线程自旋超过10次,1.6之后新增自适应锁,线程直接升级为重量级锁)同时竞争一个锁时候,会生级为轻量级锁,即每个竞争线程会在线程栈中生产一个Lock Recode去抢占当前锁,如果抢占成功的话,则在此对象的markword上面记录此LR。
3.重量级锁
自旋锁升级后,此对象则会标识为重量级锁,会在markword记录此状态。升级为重量级锁会进入锁的一个队列,设置为等待状态,默认为非公平锁,等待CPU通知。
附上对象头的不同状态的一些记录详情。
3.锁消除
即如果在方法中的锁对象只影响方法栈中,则此时就锁就没意义存在,相当于没有加锁,自然会锁消除了。
4.锁粗化
针对同一代码块多次使用同一把锁进行加锁解锁,则会粗化锁。
锁消除和粗化都是jvm优化的过程,提高效率。
5.synchoized 实现过程。
java层面: 添加synchonized 关键字。
编译字节码:monitor_enter monitor_exit 字节码会翻译成这两个指令
运行过程:执行过程中会进行锁的升级
hotstop底层实现: lock comxchg 指令实现
7.volatile
volatile 两大特点
可见性:
可以让线程之间对变量的可见。
即当一个线程修改了变量,则会通过线程总线通知其他线程在使用这个变量时候从主内存读取。
涉及到CPU缓存一致性协议。缓存行的优化。
cup之间通知其他cpu的变量修改了,需要主动从主内存中获取最新数据。
CPU有3级缓存,每个CPU存在一个或者多个内核,每个内核都有自己的1,2级缓存。线程运行在内核上面,所以每次读取数据都是先从1级缓存读取,再从2级缓存读取,最后从3级缓存读取。读取时候为了提高效率则会读取一段缓存8个字节,当线程内部修改了多个变量时候则会通知其他线程下次使用变量时候从3级缓存读取,其他线程修改也会通知。如果这几个变量在同一个缓存行则,多处修改则会同步 n*n, 但是如果多个变量不是在一个缓存行中则不提升效率(n * 2)。可以用占位符来占住缓存行的其他位置让多个变量不在同一个缓存行。
缓存一致性中包括4种状态。
S 共享。
E 独占。
I 无用。
。
内存屏障
jvm 规范是说LL SS SL LS 四种场景
L:load
S: save
即 加载 与 加载边的指令不允许指令重排,加载 与读取 边的指令不能指令重排
禁止指令重组:
代码: 添加volatile
字节码: 添加 volatile 指令。
hotstop:Lock
还是通过锁总线的方式来实现。
强弱软虚引用;
强引用:new 正常创建对象。
弱引用:sofeReference 内存不足 old gc释放此引用 ------ 适合做缓存
软引用:weakReference yang gc释放此引用。
虚引用:p… 管理堆外内存
ThreadLocal
管理线程数据,即每个线程都有一个ThreadLocalMap 对象,调用TheradLocal.set(T) 时,会从当前线程获取Map,创建Entry对象关联ThreadLocal 和 T,注意 不是map结构,但是实际上还是跟map方式差不多。