您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

在JDK1.5之前,Java的多线程都是靠synchronized来保证同步的,这会引起很多性能问题,例如死锁。但随着Java的不断完善,JNI(Java Native Interface)使得Java能越过JVM直接调用本地方法,例如CAS。

CAS是Compare And Swap(比较与交换)的缩写,它用于实现多线程同步的原子指令,允许算法执行读-修改-写操作,而无需担心其他线程同时修改变量。说人话,意思就是它的操作过程足够细微,以至于线程都奈何不了它。

所谓原子指令就是指不会被线程调度机制打断的操作指令,这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换,即要么全部完成,要么全部中断。换一种说法,就是CAS可以保证Java运算实现我们想要的操作而无需担心会受到多线程的影响。

某种程度上,CAS可以用来取代synchronized的强制同步,提升性能。其实整个java.util.concurrent包都是建立在CAS之上的,尤其是Java中大多数锁的实现基类AbstractQueuedSynchronizer,更是以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相关类结构图是:

还是老规矩,用代码来举例:

/**
* 仅用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() {
@Override
public 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() {
@Override
public void run() {
tester.increase(1);
}
};
executor.submit(runnable);
}
// 为了观察效果休眠,但实际生产环境中肯定不允许
Thread.sleep(100);
executor.shutdown();
System.out.println(tester.get());
}
}

CAS的内容并不多,可以看看它的源码,还是比较有意思的。


感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

Java多线程(5):CAS的更多相关文章

  1. Java多线程:CAS与java.util.concurrent.atomic

    锁的几种概念 悲观锁 总是假设最坏的情况,每次获取数据都认为别人会修改,所以拿数据时会上锁,一直到释放锁不允许其他线程修改数据.Java中如synchronized和reentrantLock就是这种 ...

  2. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  3. java 多线程12 : 无锁 实现CAS原子性操作----原子类

    由于java 多线程11:volatile关键字该文讲道可以使用不带锁的情况也就是无锁使变量变成可见,这里就理解下如何在无锁的情况对线程变量进行CAS原子性及可见性操作 我们知道,在并发的环境下,要实 ...

  4. Java多线程并发06——CAS与AQS

    在进行更近一步的了解Java锁的知识之前,我们需要先了解与锁有关的两个概念 CAS 与 AQS.关注我的公众号「Java面典」了解更多 Java 相关知识点. CAS(Compare And Swap ...

  5. Java多线程--CAS

    在Java多线程并发的情况下同时对一个变量进行操作会出现线程安全的问题,假如我们现在使用20个线程对一个变量不停累加1,代码如下: 1 public class ThreadDemo implemen ...

  6. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  7. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  8. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

  9. java多线程系类:JUC线程池:03之线程池原理(二)(转)

    概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...

  10. java多线程系类:JUC原子类:03之AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

随机推荐

  1. Redis 12 持久化

    参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 概述 Redi ...

  2. TS 泛型推断好难啊,看看你能写出来不

    前言 最近做东西都在用ts,有时候写比较复杂的功能,如果不熟悉,类型写起来还是挺麻烦的.有这样一个功能,在这里,我们就不以我们现有的业务来举例了,我们还是已Animal举例,来说明场景.通过一个工厂来 ...

  3. Spring源码-xml解析

    Spring使用SAX解析xml.SAX的全称是Simple APIs for XML,也即XML简单应用程序接口.与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式. ...

  4. [HNOI2010]弹飞绵羊 (平衡树,LCT动态树)

    题面 题解 因为每个点都只能向后跳到一个唯一的点,但可能不止一个点能跳到后面的某个相同的点, 所以我们把它抽象成一个森林.(思考:为什么是森林而不是树?) 子节点可以跳到父节点,根节点再跳就跳飞了. ...

  5. 【lwip】04-网络数据包流向

    目录 前言 4.1 TCPIP分层与lwip数据共享 4.2 协议栈线程模型 4.3 pbuf 结构体 4.3.1 pbuf的标志位flags 4.4 pbuf的类型 4.4.1 PBUF_RAM类型 ...

  6. 【java】学习路径18-Arrays中的sort、binarySearch使用注意

    在使用Arrays.binarySearch()的时候要注意先对数组进行排序. Arrays.binarySearch()方法介绍: Searches the specified array of i ...

  7. Java连接简单使用ElasticSearch

    目录 1. 添加依赖 2. 代码,无账号密码 3. 代码,有账号密码,并且是https方式 4. 参考文章 1. 添加依赖 <!-- https://mvnrepository.com/arti ...

  8. KingbaseES R6 集群主机锁冲突导致的主备切换案例

    ​ 案例说明: 主库在业务高峰期间,客户执行建表等DDL操作,主库产生"AccessExclusiveLock "锁,导致大量的事务产生锁冲突,大量的会话堆积,客户端session ...

  9. angr原理与实践(二)—— 各类图的生成(CFG CG ACFG DDG等)

    ​  本文系原创,转载请说明出处 Please Subscribe Wechat Official Account:信安科研人,获取更多的原创安全资讯 上一篇文章介绍了angr的原理,自此篇文章开始, ...

  10. JAVA中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器

    大家好,又见面了. 在我们的项目编码中,不可避免的会用到一些容器类,我们可以直接使用List.Map.Set.Array等类型.当然,为了体现业务层面的含义,我们也会根据实际需要自行封装一些专门的Be ...