是什么

  • 全称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的更多相关文章

  1. paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)

    paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1     锁的缺点 2     CAS(Compare ...

  2. Java乐观锁实现之CAS操作

    介绍CAS操作前,我们先简单看一下乐观锁 与 悲观锁这两个常见的锁概念. 悲观锁: 从Java多线程角度,存在着“可见性.原子性.有序性”三个问题,悲观锁就是假设在实际情况中存在着多线程对同一共享的竞 ...

  3. java 乐观锁CAS

    乐观锁是一种思想,本身代码里并没有lock或synchronized关键字进行修饰.而是采用一种version. 即先从数据库中查询一条记录得到version值,在更新这条记录时在where条件中对这 ...

  4. 深入分析 Java 乐观锁

    前言 激烈的锁竞争,会造成线程阻塞挂起,导致系统的上下文切换,增加系统的性能开销.那有没有不阻塞线程,且保证线程安全的机制呢?--乐观锁. 乐观锁是什么? 操作共享资源时,总是很乐观,认为自己可以成功 ...

  5. Java乐观锁、悲观锁

    乐观锁 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号 ...

  6. Java乐观锁的实现原理(案例)

    简要说明: 表设计时,需要往表里加一个version字段.每次查询时,查出带有version的数据记录,更新数据时,判断数据库里对应id的记录的version是否和查出的version相同.若相同,则 ...

  7. JAVA乐观锁、悲观锁实现

    一.名词解释 1.悲观锁:认为每次对数据库的操作(查询.修改)都是不安全的,因此每次操作都会把这条数据锁掉,直到本次操作完毕释放该锁 2.乐观锁:查询数据的时候总是认为是安全的,不会锁数据:等到更新数 ...

  8. java 乐观锁 vs 悲观锁

    在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 悲观锁其实就是 完全同步 比如 sync ...

  9. 乐观锁--CAS

    悲观锁与乐观锁的区别 悲观锁会把整个对象加锁占为已有后才去做操作,Java中的Synchronized属于悲观锁.悲观锁有一个明显的缺点就是:它不管数据存不存在竞争都加锁,随着并发量增加,且如果锁的时 ...

随机推荐

  1. Linux 下LAMP环境搭建_【all】

    LAMP = Linux + Apache + Mysql + PHP 0. Linux环境搭建 Linux 系统安装[Redhat] 1.http服务软件分类及企业实战用途介绍 静态程序: Apac ...

  2. + - ! function($) (), function 前面的符号意思

    如果在function之前加上感叹号 (!) 会怎么样?比如下面的代码: !function(){alert('iifksp')}()        // true 在控制台运行后得到的值时true, ...

  3. December 15th 2016 Week 51st Thursday

    At the touch of love everyone becomes a poet. 每一个沐浴在爱河中的人都是诗人. You call your love as your sweetheart ...

  4. ZT 蓝牙的AVDTP协议笔记

    我的电子杂烩饭 http://blog.sina.com.cn/wuchuchu2012 [订阅][手机订阅] 首页 博文目录 图片 关于我 个人资料 Tifnan Qing 微博 加好友 发纸条 写 ...

  5. ZT android -- 蓝牙 bluetooth (五)接电话与听音乐

    android -- 蓝牙 bluetooth (五)接电话与听音乐 分类: Android的原生应用分析 2013-07-13 20:53 2165人阅读 评论(9) 收藏 举报 蓝牙android ...

  6. 36、XmlReader与 XMLWriter(抽象类)

    一.概述 XMLReader为抽象类,其派生类有:XmlDictionaryReader.XmlNodeReader.XmlTextReader(与IO命名空间中的TextReader对象一起使用). ...

  7. codeforces 414D Mashmokh and Water Tanks

    codeforces 414D Mashmokh and Water Tanks 题意 题解 \(a_i\):第 \(i\) 层的结点个数. \(b_i\):第 \(i\) 层初始有水的结点个数. 如 ...

  8. ethereumjs/ethereumjs-blockchain-2-test

    https://github.com/ethereumjs/ethereumjs-blockchain/tree/master/test 'use strict' const test = requi ...

  9. shell脚本进阶 详解及其实例(一)

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  10. leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown

    121. Best Time to Buy and Sell Stock 题目的要求是只买卖一次,买的价格越低,卖的价格越高,肯定收益就越大 遍历整个数组,维护一个当前位置之前最低的买入价格,然后每次 ...