介绍CAS操作前,我们先简单看一下乐观锁 与 悲观锁这两个常见的锁概念。

悲观锁:

  从Java多线程角度,存在着“可见性、原子性、有序性”三个问题,悲观锁就是假设在实际情况中存在着多线程对同一共享的竞争,所以在操作前先占有共享资源(悲观态度)。因此,悲观锁是阻塞,独占的,存在着频繁的线程上下文切换,对资源消耗较大。synchronized就是悲观锁的一种实现。

乐观锁:

  如名一样,每次操作都认为不会发生冲突,尝试执行,并检测结果是否正确。如果正确则执行成功,否则说明发生了冲突,回退再重新尝试。乐观锁的过程可以分为两步:冲突检测 和 数据更新。在Java多线程中乐观锁一个常见实现即:CAS操作。

CAS

  CAS,(Compare-And-Swap,比较和替换)。其具有三个操作数:内存地址V,旧的预期值A,新的预期值B。当V中的值和A相同时,则用新值B替换V中的值,否则不执行更新。(PS:上述的操作是原子性的,因为过程是:要么执行更新,要么不更新)

  在JDK1.5新增的java.util.concurrent(J.U.C) 就是建立在CAS操作上的。CAS是一种非阻塞的实现(PS:乐观锁采用一种 “自旋锁”的技术,其原理是:如果存在竞争,则没有获得资源的线程不立即挂起,而是采用让线程执行一个忙循环(自旋)的方式,等待一段时间看是否能获得锁,如果超出规定时间再挂起),所以J.U.C在性能上有很大的提升。下面以J.U.C下的AtomicInteger的部分源码为例,看一下CAS的过程究竟如何。

public class AtomicInteger extends Number implements java.io.Serializable {
private volatile int value; public final int get() {
return value;
} public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
  // CAS操作
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
} }

  以上截取自AtomicInteger的部分源码。CAS操作的核心就在 getAndIncrement()方法中,在此方法调用的compareAndSet(int expect , int update) 的两个参数可知,当current值符合expect时,用next替换了current。如果不符合,则在for中不断尝试知道成功为止。在这里的步骤,就相当于一个原子性的 ++i 了。(PS: 单纯的 ++i 不具备原子性)

  其中,compareAndSet方法的实现得益于硬件的发展:多条步骤的操作行为可以通过一条指令完成。(在此是利用JNI来完成CPU指令的操作)

 

CAS存在的问题

1. ABA问题

 ABA问题值,内存地址V的值是A,线程one从V中取出了A,此时线程two也从V中取出了A,同时将A修改为B,但是又因为一些原因修改为A。而此时线程one仍看到V中的值为A,认为没有发生变化,此为ABA问题。解决ABA问题一种方式是通过版本号(version)。每次执行数据修改时,都需要带上版本号,如:1A,2B,3A。通过比较版本号可知是否有发生过操作,也就解决了ABA问题。  

2. 未知的等待时长

  因为CAS采取失败重试的策略,所以不确定会发生多少次循环重试。如果在竞争激烈的环境下,其重试次数可能大幅增加。此时效率也就降低了。

总结

  乐观锁、悲观锁是一种思想,CAS是乐观锁的一种实现。前者是非阻塞同步,非独占,而后者是阻塞同步,独占锁。在可预知的情况下,如果竞争冲突发生较少,乐观锁是个不错的选择。而如果竞争激烈,悲观锁应得到考虑。

  关于对象的创建分配内存,因为多线程分配对象空间并不安全,如分配A,B两对象,当给A分配内存时,指针还没修改,就切换到给B分配同一块内存,引发错误。其中一种解决方法就是通过底层的CAS操作来保证分配的原子性。

 

如有错误,敬请斧正,以防误导他人。

参考:http://www.importnew.com/20472.html

  

 

Java乐观锁实现之CAS操作的更多相关文章

  1. 深入分析 Java 乐观锁

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

  2. JAVA乐观锁实现-CAS

    是什么 全称compare and swap,一个CPU原子指令,在硬件层面实现的机制,体现了乐观锁的思想. JVM用C语言封装了汇编调用.Java的基础库中有很多类就是基于JNI调用C接口实现了多线 ...

  3. 可重入锁 & 自旋锁 & Java里的AtomicReference和CAS操作 & Linux mutex不可重入

    之前还是写过蛮多的关于锁的文章的: http://www.cnblogs.com/charlesblc/p/5994162.html <[转载]Java中的锁机制 synchronized &a ...

  4. java 乐观锁CAS

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

  5. Java乐观锁、悲观锁

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

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

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

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

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

  8. java 乐观锁 vs 悲观锁

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

  9. 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

随机推荐

  1. python初步学习-python模块之 os

    os os 模块在运维工作中是很常用的一个模块.通过os模块调用系统命令.os模块可以跨平台使用. 在 import os的时候,建议使用import os而非from os import *.这样可 ...

  2. python初步学习-面向对象之 类(二)

    方法重写 如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法: #!/usr/bin/env python #coding:utf8 class Parent: def myMeth ...

  3. 爬虫实战--基于requests和beautifulsoup的妹子网图片爬取(福利哦!)

    #coding=utf-8 import requests from bs4 import BeautifulSoup import os all_url = 'http://www.mzitu.co ...

  4. JS中短路运算符&&和||

    在JS函数中我们经常会使用到短路运算符,主要是逻辑与(&&) 和 逻辑或(||) 1.逻辑与 && 的运算方式 var a = 5 && 6; cons ...

  5. Vue.js 在 webpack 脚手架中使用 cssnext

    Vue.js 的 webpack脚手架默认已经使用了 PostCSS 的 autoprefixer 的功能. 如果想使用下一代 css语法,即cssnext: 1. 安装依赖 npm install ...

  6. python操作adb代码

    adb命令的练习 #!/usr/bin/env python # encoding: utf-8 import os import re nameplt=re.compile("packag ...

  7. anychat安装

    1.下载后,解压到一个目录 2.进入anychat核心服务器目录,并启动   ①.cd %anychat安装路径%/binrver     ②../anychatcoreserver -d   3.进 ...

  8. URAL题解三

    URAL题解三 URAL 1045 题目描述:有\(n\)个机场,\(n-1\)条航线,任意两个机场有且只有一种方案联通.现有两个恐怖分子从\(m\)号机场出发,第一个人在机场安装炸弹,乘坐飞机,引爆 ...

  9. puppet overview

    安装 以在Ubuntu server 14.04.2 TLS 为例: 设置机器名. 编辑/etc/host以修改主机名,因为puppet是基于证书的,证书中包含主机名: 更新包源. echo -e & ...

  10. aws rds

    1.还原快照,注意设置安全组的问题:不然会导致还原后连接不上: