java并发编程学习: 原子变量(CAS)
先上一段代码:
package test; public class Program { public static int i = 0; private static class Next extends Thread { public void run() {
i = i + 1;
System.out.println(i);
}
} public static void main(String[] args) {
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Next());
threads[i].start();
}
}
}
代码很简单,10个线程,1个共享变量,每个线程在run的时候,将变量+1,反复运行多次,可能会输出类似下面的结果:
1
4
3
6
2
5
7
8
9
9
最后输出了2个9,显然有2个线程打架了,原因:
i = i + 1,虽然只有一行代码,但在计算机内部执行时,至少会拆成3条指令
a) 读取 i 的值,将其复制到本地的(副本)变量中
b) 将本地变量值+1
c) 将本地变量的值,覆盖到 i 上
假如有2个线程先后到达步骤a),但尚未完成步骤b),这时就出问题了,会生成相同的值。要解决这个问题,当然可以通过加锁(或synchronized),类似下面这样,代价是牺牲性能。
private static class Next extends Thread { public void run() {
synchronized (this) {
i = i + 1;
}
System.out.println(i);
}
}
jdk的并发包里提供了很多原子变量,可以在"不加锁"(注:OS底层其实还是有锁的,只不过相对java里的synchronized性能要好很多)的情况下解决这个问题,参考下面的用法:
package test; import java.util.concurrent.atomic.AtomicInteger; public class Program { public static AtomicInteger i = new AtomicInteger(0); private static class Next extends Thread { public void run() {
int x = i.incrementAndGet();
System.out.println(x);
}
} public static void main(String[] args) {
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Next());
threads[i].start();
}
}
}
实现原理,可以从源码略知一二:
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
1、最外层是一个死循环
2、先获取旧值,将其复制到一个局部变量上
3、将局部变量值+1
4、比较旧值是否变化,如果没变化,说明没有其它线程对旧值修改,直接将新值覆盖到旧值,并返回新值,退出循环
5、如果旧值被修改了,开始下一轮循环,重复刚才这一系列操作,直到退出循环。
所以,第4步的compareAndSet其实是关键,继续看源码:
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
最终看到的是一个native方法(说明依赖不同OS的原生实现)
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
再往下跟,就得有点c++/c/汇编功底了,有兴趣的可自己研究下参考文章中的第2个链接文章
参考文章:
http://ifeve.com/concurrent-collections-8/
http://www.blogjava.net/mstar/archive/2013/04/24/398351.html
java并发编程学习: 原子变量(CAS)的更多相关文章
- Java并发编程之原子变量
原子变量最主要的一个特点就是所有的操作都是原子的,synchronized关键字也可以做到对变量的原子操作.只是synchronized的成本相对较高,需要获取锁对象,释放锁对象,如果不能获取到锁,还 ...
- Java并发编程学习前期知识下篇
Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...
- Java并发指南开篇:Java并发编程学习大纲
Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中 ...
- Java并发编程学习路线(转)
以前特地学过并发编程,但是没怎么学进去,不太喜欢.最近发现,作为一个资深工程师,却没有完整深入系统的学习过,而反是现在的BAT大并发是必须的,感觉甚是惭愧. 故找了一片学习文章,如下,准备集中一段时间 ...
- Java并发编程学习路线
一年前由于工作需要从微软技术栈入坑Java,并陆陆续续做了一个Java后台项目,目前在搞Scala+Java混合的后台开发,一直觉得并发编程是所有后台工程师的基本功,所以也学习了小一年Java的并发工 ...
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- 学习笔记:java并发编程学习之初识Concurrent
一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...
- Java并发编程学习:volatile关键字解析
转载:https://www.cnblogs.com/dolphin0520/p/3920373.html 写的非常棒,好东西要分享一下 Java并发编程:volatile关键字解析 volatile ...
- [Todo] Java并发编程学习
有两个系列的博文,交替着可以看看: 1. Java并发编程与技术内幕 http://blog.csdn.net/Evankaka/article/details/51866242 2. [Java并发 ...
随机推荐
- JAVA理解逻辑程序的书上全部重要的习题
今天随便翻翻看以前学过JAVA理解逻辑程序的书上全部练习,为了一些刚学的学弟学妹,所以呢就把这些作为共享了. 希望对初学的学弟学妹有所帮助! 例子:升级“我行我素购物管理系统”,实现购物结算功能 代码 ...
- css之颜色值、单位
颜色值 英文命令颜色:p{color:red;} RGB颜色:p{color:rgb(133,45,200);}每一项的值可以是 0~255 之间的整数,也可以是 0%~100% 的百分数.如:p{c ...
- jQuery静态方法globalEval使用和源码分析
Eval函数大家都很熟悉,但是globalEval方法却很少使用,大多数参考手册也没有相关api,下面就对其用法和源码相应介绍: jQuery.globalEval()函数用于全局性地执行一段Java ...
- CSS3图片翻转切换案例及其中重要属性解析
图片翻转切换,在不使用CSS3的情况下,一般都是使用JS实现动画,同时操作元素的width和left,或者height和top以模拟翻转的效果,并在适当时候改变src或者z-index实现图片切换. ...
- 学习zepto.js(对象方法)[3]
继续说zepto里attributes的相关操作. attr,removeAttr,prop这三个方法. attr(): 三种用途 get: 返回值为一个string字符串 $("<s ...
- 好用的第三方控件,Xcode插件(不断更新)
第三方控件类: 1.提示框 MBProgressHUD: 是一款非常强大的.提供多种样式的提示框.使用起来简单.方便.可以在GitHub上查看具体的使用方法. https://github.com ...
- mac osx get postgresql path
sudo lsof -i :5433 ps xuwww -p 91 sudo port install py27-psycopg2
- IT人经济思维之投资 - 创业与投资系列文章
前面笔者写过一个文(IT从业者的职业规划),主要通过笔者的从业道路的经验,介绍了IT从业者的职业选择道路问题,主要从技术.业务和管理三大方面进行了描述.然后,通过文(IT从业者的职业道路(从程序员到部 ...
- 查看Linux版本信息
如何查看Linux系统使用的版本信息呢? 下面这篇文章收集.整理了一些常见的查看Linux系统版本的方法.由于手头只有Oracle Linux.Centos Linux.Redhat Linux三个版 ...
- SQL Server解决孤立用户浅析
孤立用户概念 所谓孤立用户即指在服务器实例上未定义或错误定义了其相应 SQL Server 登录名的数据库用户无法登录到实例. 这样的用户被称为此服务器实例上的数据库的"孤立用 ...