JAVA乐观锁实现-CAS
是什么
- 全称compare and swap,一个CPU原子指令,在硬件层面实现的机制,体现了乐观锁的思想。
- JVM用C语言封装了汇编调用。Java的基础库中有很多类就是基于JNI调用C接口实现了多线程同步更新的功能。
原理
CMS有三个操作数:当前主内存变量的值V,线程本地变量预期值A,线程本地待更新值B。当需要更新变量值的时候,会先获取到内存变量值V然后很预期值A进行比较,如果相同则更新为B,如果不同,则将最新的变量值更新到预期值中再重新尝试上面的步骤,直到成功为止。
举例
以基于CAS实现的AtomicInteger 类进行讲解。
我们先写一个多线程,对同一个数据类进行分别进行加减操作10000次,正确的结果应该还是0。
没有任何多线程同步机制的代码如下:
package priv.nanjing.testCasClass; /*
* @Author : darrenqiao
* */ //多线程争用的数据类
class Counter {
int count = 0; public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public void add() {
count += 1;
} public void dec() {
count -= 1;
}
} //争用数据做加操作的线程
class AddDataThread extends Thread { Counter counter; public AddDataThread(Counter counter) {
this.counter = counter;
} @Override
public void run() {
for (int i = 0; i < CasClass.LOOP; ++i) {
counter.add();
}
}
} //争用数据做减法操作的线程
class DecDataThread extends Thread { Counter counter; public DecDataThread(Counter counter) {
this.counter = counter;
} @Override
public void run() {
for (int j = 0; j < CasClass.LOOP; j++) {
counter.dec();
}
}
} public class CasClass {
final static int LOOP = 10000; public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread addThread = new AddDataThread(counter);
Thread decThread = new DecDataThread(counter);
addThread.start();
decThread.start();
addThread.join();
decThread.join();
System.out.println(counter.getCount());
} }
以下是三次执行结果,每一次都不一样。

为什么会出现这个结果呢?
因为 count += 1 / count -= 1 通过javap反编译Count.class文件,可以看出对应的字节码是三条指令
//count += 1
5: iconst_1
6: iadd
7: putfield #12 // Field count:I //count 1= 1
5: iconst_1
6: isub
7: putfield #12 // Field count:I
所以多线程切换是,可能会造成数据更新的不同步,怎么解决呢?
就是对被操作的数据加锁,可以是悲观锁,可以是乐观锁,这里使用的就是基于乐观锁实现的AtomicInteger类
package priv.nanjing.testCasClass; import java.util.concurrent.atomic.AtomicInteger; /*
* @Author : darrenqiao
* */ //多线程争用的数据类
class Counter {
//int count = 0;
//使用AtomicInteger代替基本数据类型
AtomicInteger count = new AtomicInteger(0); public int getCount() {
//return count;
return count.get();
} public void add() {
//count += 1;
count.addAndGet(1);
} public void dec() {
//count -= 1;
count.decrementAndGet();
}
} //争用数据做加操作的线程
class AddDataThread extends Thread { Counter counter; public AddDataThread(Counter counter) {
this.counter = counter;
} @Override
public void run() {
for (int i = 0; i < CasClass.LOOP; ++i) {
counter.add();
}
}
} //争用数据做减法操作的线程
class DecDataThread extends Thread { Counter counter; public DecDataThread(Counter counter) {
this.counter = counter;
} @Override
public void run() {
for (int j = 0; j < CasClass.LOOP; j++) {
counter.dec();
}
}
} public class CasClass {
final static int LOOP = 10000; public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread addThread = new AddDataThread(counter);
Thread decThread = new DecDataThread(counter);
addThread.start();
decThread.start();
addThread.join();
decThread.join();
System.out.println(counter.getCount());
} }
执行多次,会发现,结果只有一个:0.这样就保证了数据更新的原子性。

那么CAS有什么缺点需要注意?
- ABA问题:我内存对象从A变成B在变成A,CAS会当成没有变化,进而去更新值,实际是有变化的。
- 循环时间开销大:一直和预期值不对的情况下,会一直循环。
- 只能保证一个共享变量的原子操作。
JAVA乐观锁实现-CAS的更多相关文章
- paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)
paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1 锁的缺点 2 CAS(Compare ...
- Java乐观锁实现之CAS操作
介绍CAS操作前,我们先简单看一下乐观锁 与 悲观锁这两个常见的锁概念. 悲观锁: 从Java多线程角度,存在着“可见性.原子性.有序性”三个问题,悲观锁就是假设在实际情况中存在着多线程对同一共享的竞 ...
- java 乐观锁CAS
乐观锁是一种思想,本身代码里并没有lock或synchronized关键字进行修饰.而是采用一种version. 即先从数据库中查询一条记录得到version值,在更新这条记录时在where条件中对这 ...
- 深入分析 Java 乐观锁
前言 激烈的锁竞争,会造成线程阻塞挂起,导致系统的上下文切换,增加系统的性能开销.那有没有不阻塞线程,且保证线程安全的机制呢?--乐观锁. 乐观锁是什么? 操作共享资源时,总是很乐观,认为自己可以成功 ...
- Java乐观锁、悲观锁
乐观锁 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号 ...
- Java乐观锁的实现原理(案例)
简要说明: 表设计时,需要往表里加一个version字段.每次查询时,查出带有version的数据记录,更新数据时,判断数据库里对应id的记录的version是否和查出的version相同.若相同,则 ...
- JAVA乐观锁、悲观锁实现
一.名词解释 1.悲观锁:认为每次对数据库的操作(查询.修改)都是不安全的,因此每次操作都会把这条数据锁掉,直到本次操作完毕释放该锁 2.乐观锁:查询数据的时候总是认为是安全的,不会锁数据:等到更新数 ...
- java 乐观锁 vs 悲观锁
在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 悲观锁其实就是 完全同步 比如 sync ...
- 乐观锁--CAS
悲观锁与乐观锁的区别 悲观锁会把整个对象加锁占为已有后才去做操作,Java中的Synchronized属于悲观锁.悲观锁有一个明显的缺点就是:它不管数据存不存在竞争都加锁,随着并发量增加,且如果锁的时 ...
随机推荐
- cygwin64-安装包管理工具
1.dos command, install pkg $ setup-x86_64.exe -q -P curl $ setup-x86_64.exe -q -P lynx 2. cygwin64 c ...
- flash 动画展示
- ASP.NET Core 返回文件、用户下载文件,从网站下载文件,动态下载文件
ASP.NET Core 中,可以在静态目录添加文件,直接访问就可以下载.但是这种方法可能不安全,也不够灵活. 我们可以在 Controller 控制器中 添加 一个 Action,通过此Action ...
- PHPmyadmin拿shell总结
PHPmyadmin修改用户密码 直接点击上面的localhost或者1270.0.1,出现用户一栏,点击修改即可 添加超级用户guetsec密码ooxx并且允许外连 GRANT ALL PRIVIL ...
- Debian 9 vsftpd: version 3.0.3 配置
现在网上关于vsftpd的资料不少,但是版本已经比较老,配置起来各种错误,耽误不少时间,现将配置步骤更新如下,配置环境版本:Debian 9 + vsftpd: version 3.0.3 1.apt ...
- 洛谷 P4705 玩游戏
题目分析 题目要求的是: \[ \sum_{i=1}^n\sum_{j=1}^m(a_i+b_j)^x(x\in [1,T]) \] 利用二项式定理化式子, \[ \begin{aligned} &a ...
- BZOJ1468:Tree(点分治)
Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是 ...
- java基础——回文数判断
/** * 题目描述: * 有这样一类数字,他们顺着看和倒着看是相同的数,例如:121,656,2332等,这样的数字就称为:回文数字.编写一个函数,判断某数字是否是回文数字. * 要求实现方法: * ...
- 减少 lwip 消耗 的 RAM
1.修改 最大一包数据的大小 TCP_MSS , 即 TCP最大报文段大小,根据自己的应用进行修改 比如 我 的一包数据最大 256字节,在 lwipopts.h 文件中 因此 修改 如下: /* ...
- CentOS7开发环境搭建
BIOS开启VT支持 查询笔记本进入BIOS的按键,启动BIOS的虚拟化设置 假设安装360卫士,那么请永久关闭Intel-VT核晶防护引擎 CentOS DNS配置 Linux 下设置DNS位置有3 ...