java多线程之CAS
前言
在Java并发包中有这样一个包,java.util.concurrent.atomic,该包是对Java部分数据类型的原子封装,在原有数据类型的基础上,提供了原子性的操作方法,保证了线程安全。下面以AtomicInteger为例,来看一下是如何实现的。

public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}


public final int decrementAndGet() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return next;
}
}

以这两个方法为例,incrementAndGet方法相当于原子性的++i,decrementAndGet方法相当于原子性的--i(根据第一章和第二章我们知道++i或--i不是一个原子性的操作),这两个方法中都没有使用阻塞式的方式来保证原子性(如Synchronized),那它们是如何保证原子性的呢,下面引出CAS。
Compare And Swap
CAS 指的是现代 CPU 广泛支持的一种对内存中的共享数据进行操作的一种特殊指令。这个指令会对内存中的共享数据做原子的读写操作。简单介绍一下这个指令的操作过程:首先,CPU 会将内存中将要被更改的数据与期望的值做比较。然后,当这两个值相等时,CPU 才会将内存中的数值替换为新的值。否则便不做操作。最后,CPU 会将旧的数值返回。这一系列的操作是原子的。它们虽然看似复杂,但却是 Java 5 并发机制优于原有锁机制的根本。简单来说,CAS 的含义是“我认为原有的值应该是什么,如果是,则将原有的值更新为新值,否则不做修改,并告诉我原来的值是多少”。(这段描述引自《Java并发编程实践》)
简单的来说,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则返回V。这是一种乐观锁的思路,它相信在它修改之前,没有其它线程去修改它;而Synchronized是一种悲观锁,它认为在它修改之前,一定会有其它线程去修改它,悲观锁效率很低。下面来看一下AtomicInteger是如何利用CAS实现原子性操作的。
CAS的ABA问题
所谓 ,问题基本是这个样子:
- 进程P1在共享变量中读到值为A
- P1被抢占了,进程P2执行
- P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。
- P1回来看到共享变量里的值没有被改变,于是继续执行。
虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。ABA问题最容易发生在lock free 的算法中的,CAS首当其冲,因为CAS判断的是指针的地址。如果这个地址被重用了呢,问题就很大了。(地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址)
比如上述的DeQueue()函数,因为我们要让head和tail分开,所以我们引入了一个dummy指针给head,当我们做CAS的之前,如果head的那块内存被回收并被重用了,而重用的内存又被EnQueue()进来了,这会有很大的问题。(内存管理中重用内存基本上是一种很常见的行为)
这个例子你可能没有看懂,维基百科上给了一个活生生的例子——
你拿着一个装满钱的手提箱在飞机场,此时过来了一个火辣性感的美女,然后她很暖昧地挑逗着你,并趁你不注意的时候,把用一个一模一样的手提箱和你那装满钱的箱子调了个包,然后就离开了,你看到你的手提箱还在那,于是就提着手提箱去赶飞机去了。
这就是ABA的问题。
摘自:http://www.cnblogs.com/lintong/p/4373723.html
java多线程之CAS的更多相关文章
- java多线程之CAS原理
前言 在Java并发包中有这样一个包,java.util.concurrent.atomic,该包是对Java部分数据类型的原子封装,在原有数据类型的基础上,提供了原子性的操作方法,保证了线程安全.下 ...
- Java高性能编程之CAS与ABA及解决方法
Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...
- Java多线程之ConcurrentSkipListMap深入分析(转)
Java多线程之ConcurrentSkipListMap深入分析 一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- JAVA多线程之wait/notify
本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- java多线程之yield,join,wait,sleep的区别
Java多线程之yield,join,wait,sleep的区别 Java多线程中,经常会遇到yield,join,wait和sleep方法.容易混淆他们的功能及作用.自己仔细研究了下,他们主要的区别 ...
- Java多线程之Runnable与Thread
Java多线程之Thread与Runnable 一.Thread VS Runnable 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类和 ...
- JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止
JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止 背景 当单线程的程序发生一个未捕获的异常时我们可以采用try....catch进行异常的捕获,但是在多线程环境 ...
随机推荐
- Sql用变量拼语句
CREATE PROC Test_GetCollegeInfo @type int AS BEGIN ),@v int,@sql nvarchar(max) Begin )) END ELSE BEG ...
- 使用复合索引代替单键索引,来避免单键有null值的情况
查看原表: SQL> select count(*) from t1; COUNT(*) ---------- 3229088 SQL> select count(*) from t1 w ...
- 0511 backlog
SCRUM 这次的作业就是确定SCRUM的计划,确定sprint backlog的一个冲刺周期,而这个周期是两个星期.争取在两周内发布1.0版本. 本次作业以网站构建为主: ID NAME ...
- 纯CSS实现帅气的SVG路径描边动画效果(转载)
本文转载自: 纯CSS实现帅气的SVG路径描边动画效果
- Web应用程序项目以配置使用IIS。未找到Web服务器
解决办法 右键编辑该Web项目的csproj文件 把UserIIS改为False.或者在IIS服务器里面配置一个IISUrl里面的地址 如图
- BootStrap tabs标签 使用fade效果首次加载页面不能显示内容
<div class="tab-pane active fade" id="home"> <div class="alert ale ...
- Create and Use Custom Attributes
http://www.codeproject.com/Articles/1811/Creating-and-Using-Attributes-in-your-NET-applicat Create a ...
- php strrpos()与strripos()函数不同之处在哪里呢
strripos() 函数 定义和用法strripos() 函数查找字符串在另一个字符串中最后一次出现的位置.如果成功,则返回位置,否则返回 false.语法strrpos(string,find,s ...
- Mac下面的SecureCRT(附破解方案) 更新到最新的8.0.2
继续更新到8.0.2的破解,整体的破解方案都发生了的变化首先还是去 http://macabc.com/detail.htm?app_id=24 下载最新的8.0.2介于很多小白说替换之后说文件损坏, ...
- jQuery validation学习(2)验证身份证
验证邮编 jQuery.validator.addMethod("isZipCode", function(value, element) { -]{}$/; return thi ...