锁、volatile、CAS 比较
一。锁的劣势
(1) 在JDK1.5之前都是使用synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程持有守
护变量的锁,都采用独占的方式来访问这些变量
(2)如果出现多个线程同时访问锁,则一些线程将被挂起,当线程恢复执行时,必须等待其它线程执行完他们的时间片以后才能被调度执行,在挂起和
恢复执行过程中存在着很大的开销
(3)当一个线程正在等待锁时,它不能做任何事
(4)如果一个线程在持有锁的情况下被延迟执行,那么所有需要这个锁的线程都无法执行下去
(5)如果被阻塞的线程优先级高,而持有锁的线程优先级低,将会导致优先级反转
二。volatile的优势
(6)与锁相比,volatile变量是一和更轻量级的同步机制,因为在使用这些变量时不会发生上下文切换和线程调度等操作
(7)volatile变量也存在一些局限:不能用于构建原子的复合操作,因此当一个变量依赖旧值时就不能使用volatile变量
三。CAS操作
(8) Compare and Swap,CPU指令,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”
(9)CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂
起,而是被告知这次竞争中失败。这种基于冲突检测的乐观并发策略,当线程数目非常多的情况下,失败的概率会指数型增加。
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }
四。JVM对CAS的支持
(10)在JDK1.5中引入了底层的支持,在Integer,Long等类型上都公开了 CAS的操作,并且JVM把它们编译为底层硬件提供的最有效的方法,
在运行CAS的平台上,运行时把它们编译为相应的机器指令,如果处理器不支持CAS指 令,那么JVM将使用自旋锁。
(11)在CAS操作中,在更新之前先判断V的值是否仍然A,如果是的话就继续执行更新操作,但是有的时候还需要知道“自从上次看到V的值为A
以后,这个值是否发生了变化”
(12)解决方案:更新两个值:【引用,版本号】,即使这个值由A变为B,然后为变为A,版本号也是不同的。AtomicStampedReference更
新一个“对象-引用”二元组,通过在引用上加上“版本号”,从而避免ABA问题,AtomicMarkableReference将更新一个“对象引用-布尔值”的二元 组。
相关内容
IBM系列: Java理论和实践