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属于悲观锁.悲观锁有一个明显的缺点就是:它不管数据存不存在竞争都加锁,随着并发量增加,且如果锁的时 ...
随机推荐
- linux,强大的history命令
如果你经常使用 Linux 命令行,那么使用 history(历史)命令可以有效地提升你的效率.本文将通过实例的方式向你介绍 history 命令的 15 个用法. 使用 HISTTIMEFORMAT ...
- 在NGUI中高效优化UIScrollView之UIWrapContent的简介以及使用
前言: 1.我使用的NGUI版本为 v3.7.5,不知道老版的NGUI是否有UIWrapContent 这个脚本. 2.本文讲解主要以图片显示的例子为主,本文例子UIScrollView是水平方向,一 ...
- iso、ios、osi的区别
ISO 国际标准化组织(International Organization for Standardization)简称ISO,是一个全球性的非政府组织,是国际标准化领域中一个十分重要的组织.IS ...
- Linux Reboot And Poweroff Command
1.Environment:RedHat Linux Enterprise 6+Vmware Workstation 12 Pro 2.Linux shutdown and restart comma ...
- Excel工资表
- [C++]auto_ptr绑定到指针
接受指针的构造函数为explicit构造函数,所以必须使用初始化的直接形式来创建auto_ptr对象: auto_ptr<int> pi = new int(1024);//error a ...
- Salesforce和SAP Netweaver里数据库表的元数据设计
从Salesforce官网可以了解到Salesforce的force.com平台里数据库表的设计:https://developer.salesforce.com/page/Multi_Tenant_ ...
- 如何把GitHub中的开源项目导入到Eclipse
准备: 1.需要注册GitHub的账号,并找到自己想导入的项目 2.在Eclipse的help-->Marketplace中搜索egit插件,然后安装 操作步骤: 1.有三种导入方式HTTP.S ...
- MySQL 触发器-更新字段时,status列会加一
需求:当更新列中的字段时,列中的status字段,就会+1 表结构 CREATE TABLE `test_1` ( `id` int(11) DEFAULT NULL, `name` varchar( ...
- python操作mysql二
游标 游标是一种能从包括多条数据记录的结果集中每次提取一条记录的机制,游标充当指针的作用,尽管游标能遍历结果中的所有行,但它一次只指向一行,游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行 ...