目录
1、CAS算法
Cas(Compare and Swap),传入有三个值V、a、b,V是内存值,a是预期值,b是更新值,当事务提交时,从内存中获取值V,并与传入的预期值a比较,若两者相等,则将a值更新为b;否则不做任何操作或重新进行操作。CAS算法实际是一种乐观锁,自旋锁是基于此实现;底层利用CPU指令保证原子性;只对单一指针/值起作用。
2、Synchronized实现原理
对象头中的Mark Word部分,会记录当前持有对象的线程ID以及是什么锁(轻量级锁、偏向锁、重量级锁等)。轻量级锁会使用CAS尝试改变持有锁的线程ID和锁的标志位,若成功则获取锁;偏向锁连CAS算法都不使用,进一步减小开销。偏向锁会先膨胀为轻量级锁,轻量级锁又会膨胀为重量级锁。
3、锁优化
(1) 自旋锁
用一个死循环来尝试获取锁,若失败则继续获取,直到获取到所需资源的锁。
(2) 适应性自旋锁
根据前一次自旋状态,修改自旋次数等。
(3) 锁消除
对于不可以逃逸的对象,消除锁,例如局部变量中的vector、StringBuffer等线程安全对象。
(4) 锁粗化
将多个连续的加锁、解锁合并成一个锁。
(5) 偏向锁
线程执行完之后不会释放锁,直到下一个线程来时判断是否为上一次使用的线程,若是则可以直接使用;适用于在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,可以减少加锁解锁的CAS操作;当出现多线程竞争时会先变为轻量级锁。
(6) 轻量级锁
在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗;出现多线程竞争时会膨胀为重量级锁。
(7) 乐观锁
一般的实现乐观锁的方式就是记录数据版本,实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。即在事务提交时检查,若版本号或时间戳与之前获取的不一样,则说明在此之前已经有其他线程对其修改,本线程需要重新执行事务。
(8) 悲观锁
一般使用 select ...for update 对所选择的数据进行加锁(悲观锁)处理。
4、i++是否线程安全
不是线程安全的,i++ 在 cpu 中实际分为三步操作,
temp = i;
temp2 = temp + 1;
i = temp2;
这三步并没有加锁,因此不是线程安全的,不同线程执行i++可能会导致覆盖更新的问题。可以AtomicInteger 类来保证线程安全,其底层使用的是cas算法。