5 Java多线程:CAS

您好 , 我是湘王 , 这是我的博客园 , 欢迎您来 , 欢迎您再来~
在JDK1.5之前 , Java的多线程都是靠synchronized来保证同步的 , 这会引起很多性能问题 , 例如死锁 。但随着Java的不断完善 , JNI(Java Native Interface)使得Java能越过JVM直接调用本地方法 , 例如CAS 。
CAS是Compare And Swap(比较与交换)的缩写 , 它用于实现多线程同步的原子指令 , 允许算法执行读-修改-写操作 , 而无需担心其他线程同时修改变量 。说人话 , 意思就是它的操作过程足够细微 , 以至于线程都奈何不了它 。
【5 Java多线程:CAS】所谓原子指令就是指不会被线程调度机制打断的操作指令 , 这种操作一旦开始 , 就一直运行到结束 , 中间不会有任何线程切换 , 即要么全部完成 , 要么全部中断 。换一种说法 , 就是CAS可以保证Java运算实现我们想要的操作而无需担心会受到多线程的影响 。
某种程度上 , CAS可以用来取代synchronized的强制同步 , 提升性能 。其实整个java.util.concurrent包都是建立在CAS之上的 , 尤其是Java中大多数锁的实现基类AbstractQueuedSynchronizer , 更是以CAS为基础 , 提供了一系列的独占锁、共享锁、可重入锁、自旋锁、读写锁等多线程控制手段(这在后面会说) 。就像图中那样:

5 Java多线程:CAS

文章插图
Java对CAS的实现都在java.util.concurrent.atomic包下(java.util.concurrent也简称JUC , 这是个简称 。所以如果有面试官说想让你谈谈JUC相关的问题 , 不要一脸懵 , 否则会被立即淘汰) 。以AtomicInteger为例 , 从源码可以看出CAS操作都是通过sun包下Unsafe类实现 , 而Unsafe类中的方法都是native方法 , 由本地实现 , 和操作系统、CPU都有关系 。CAS有一个比较通用的实现模式:
1、首先声明(共享)变量为volatile
2、然后使用CAS的原子条件来更新
3、同时配合volatile的可见性来实现线程之间的同步
前面讲过 , 不用深究volatile关键字的用途 , 因为随着机器配置的豪华 , 其实这个关键字已经没啥用了 , 而且也可以看到 , 在CAS里面也有大量出现 , JDK已经替你用好了 , 自己如果不太熟悉就不要用了 。CAS相关类结构图是:
5 Java多线程:CAS

文章插图
还是老规矩 , 用代码来举例:
/** * 仅用AtomicInteger实现CAS * * @author 湘王 */public class AtomicIntegerTester1 {// 使用AtomicInteger实现CAS , 有没有volatile都不影响public static volatile AtomicInteger atomicInteger = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 20; i++) {Runnable runnable = new Runnable() {@Overridepublic void run() {atomicInteger.getAndIncrement();}};executor.submit(runnable);}// 为了观察效果休眠 , 但实际生产环境中肯定不允许Thread.sleep(100);executor.shutdown();System.out.println(atomicInteger.get());}}/** * 用AtomicIntegerFieldUpdater实现CAS * * @author 湘王 */public class AtomicIntegerTester2 {/** 使用AtomicIntegerFieldUpdater实现CAS , 相关计算字段必须用volatile修饰 , 不然抛异常* Caused by: java.lang.IllegalArgumentException: Must be volatile type**/public volatile int count = 0;public static final AtomicIntegerFieldUpdater<AtomicIntegerTester2> lockUpdate = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerTester2.class, "count");public int increase(int inc) {return lockUpdate.addAndGet(this, inc);}public int get() {return lockUpdate.get(this);}public static void main(String[] args) throws InterruptedException {AtomicIntegerTester2 tester = new AtomicIntegerTester2();ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 20; i++) {Runnable runnable = new Runnable() {@Overridepublic void run() {tester.increase(1);}};executor.submit(runnable);}// 为了观察效果休眠 , 但实际生产环境中肯定不允许Thread.sleep(100);executor.shutdown();System.out.println(tester.get());}}

经验总结扩展阅读