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属于悲观锁.悲观锁有一个明显的缺点就是:它不管数据存不存在竞争都加锁,随着并发量增加,且如果锁的时 ...
随机推荐
- 使用UILabel实现滚动字幕移动效果
使用UILabel实现滚动字幕移动效果 这个链接中的代码也实现了这种效果 https://github.com/cbpowell/MarqueeLabel 最终效果如下: 原理如下: 1. 获取文本 ...
- 将一种cell当做几种cell使用
将一种cell当做几种cell使用 将一种cell当做几种cell用是有着一些意义的,比如,有时候,不同的cell之间差异很小,如果再派生一个cell出来,就会显得很麻烦,这时候,将这个cell当做几 ...
- python面向对象编程(2)—— 实例属性,类属性,类方法,静态方法
1 实例属性和类属性 类和实例都是名字空间,类是类属性的名字空间,实例则是实例属性的名字空间. 类属性可通过类或实例来访问.只有通过类名访问时,才能修改类属性的值. 例外的一种情况是,当类属性是一个 ...
- 搭建spring boot+elasticsearch+activemq服务
目前时间是:2017-01-24 本文不涉及activemq的安装 需求 activemq实时传递数据至服务 elasticsearch做索引 对外开放查询接口 完成全文检索 环境 jdk:1.8 s ...
- Oracle数据库用户名密码【转载自百度经验】
登录到安装oracle数据库服务器的操作系统.打开命令窗口:(我的演示机器是windows) 查看环境变量ORACLE_SID的设置情况: windows: echo %ORACLE_SID% l ...
- JavaScript设计模式之设计原则
何为设计 即按照哪一种思路或者标准来实现功能,功能相同,可以有不同的设计方案来实现 伴随着需求的增加,设计的作用就会体现出来,一般的APP每天都在变化,更新很快,需求不断在增加,如果设计的不好,后面很 ...
- Owin+ASP.NET Identity浅析系列(二)扩展用户属性
在今天,读书有时是件“麻烦”事.它需要你付出时间,付出精力,还要付出一份心境.--仅以<Owin+ASP.NET Identity浅析系列>来祭奠那逝去的…… 上一篇博客讲了用户登录注册问 ...
- nDPI 的论文阅读和机制解析
nDPI: Open-Source High-Speed Deep Packet Inspection Wireless Communications & Mobile Computing C ...
- 阅读基于sketch的软件定义网络测量数据平面硬件模型
概要 硬件实现 基于sketch 功能:采集包数.流长数据,恢复五元组 重点:高速条件下性能较好,节省硬件资源 摘要: 提出一种基于sketch 数据结构的软件定义测量数据平面硬件模型,并在以现场可编 ...
- 记一次jvm异常排查及优化
为方便自己查看,根据工作遇到的问题,转载并整理以下jvm优化内容 有次接到客服反馈,生产系统异常,无法访问.接到通知紧急上后台跟踪,查看了数据库死锁情况--正常,接着查看tomcat 内存溢出--正常 ...