先上一段代码:

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

http://ifeve.com/13840/

java并发编程学习: 原子变量(CAS)的更多相关文章

  1. Java并发编程之原子变量

    原子变量最主要的一个特点就是所有的操作都是原子的,synchronized关键字也可以做到对变量的原子操作.只是synchronized的成本相对较高,需要获取锁对象,释放锁对象,如果不能获取到锁,还 ...

  2. Java并发编程学习前期知识下篇

    Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...

  3. Java并发指南开篇:Java并发编程学习大纲

    Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中 ...

  4. Java并发编程学习路线(转)

    以前特地学过并发编程,但是没怎么学进去,不太喜欢.最近发现,作为一个资深工程师,却没有完整深入系统的学习过,而反是现在的BAT大并发是必须的,感觉甚是惭愧. 故找了一片学习文章,如下,准备集中一段时间 ...

  5. Java并发编程学习路线

    一年前由于工作需要从微软技术栈入坑Java,并陆陆续续做了一个Java后台项目,目前在搞Scala+Java混合的后台开发,一直觉得并发编程是所有后台工程师的基本功,所以也学习了小一年Java的并发工 ...

  6. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

  7. 学习笔记:java并发编程学习之初识Concurrent

    一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...

  8. Java并发编程学习:volatile关键字解析

    转载:https://www.cnblogs.com/dolphin0520/p/3920373.html 写的非常棒,好东西要分享一下 Java并发编程:volatile关键字解析 volatile ...

  9. [Todo] Java并发编程学习

    有两个系列的博文,交替着可以看看: 1. Java并发编程与技术内幕 http://blog.csdn.net/Evankaka/article/details/51866242 2. [Java并发 ...

随机推荐

  1. SOA的浅析

    曾今SOA的概念犹如今日“云计算.大数据”一样,被炒得火热,不少企业便纷纷响应,并宣称会拥抱和实施SOA.而事实上,业界出现了两种极端:一种是由于各类文章和书籍关于SOA的描述往往太过抽象,再加上各大 ...

  2. if语句,case语句

    1.句式:if...then.判断赋值 例: if RadioButton1.Checked then sex:='男' else if RadioButton2.Checked then sex:= ...

  3. Javascript中构造函数与new命令

    典型的面向对象编程语言(比如C++和Java),存在“类”(class)这个概念.所谓“类”就是对象的模板,对象就是“类”的实例.但是,在JavaScript语言的对象体系,不是基于“类”的,而是基于 ...

  4. asp.net mvc 中 一种简单的 URL 重写

    asp.net mvc 中 一种简单的 URL 重写 Intro 在项目中想增加一个公告的功能,但是又不想直接用默认带的那种路由,感觉好low逼,想弄成那种伪静态化的路由 (别问我为什么不直接静态化, ...

  5. 开发培训及技术研讨会PPT下载链接

    8月到9月,我们做了一圈巡回演出,脚步踏遍祖国大江南北,包括沈阳.武汉.深圳.香港.上海和北京等几个城市,给大家带来Autodesk最新的云技术和桌面产品技术动态,得到了大家的热烈响应.感谢各位合作伙 ...

  6. Objective-C内存管理之-引用计数

    本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...

  7. [C#6] 0-概览

    1. C#6 新特性图谱 C#6的新特性主要由编译器(“Roslyn”)带来,并不依赖CLR和.NET Framework的升级,我们可以认为这个版本的新语言特性的主要目的为了简化代码书写方式,让我们 ...

  8. 细说ASP.NET Forms身份认证

    阅读目录 开始 ASP.NET身份认证基础 ASP.NET身份认证过程 如何实现登录与注销 保护受限制的页面 登录页不能正常显示的问题 认识Forms身份认证 理解Forms身份认证 实现自定义的身份 ...

  9. Jsoup解析html终于成功了!!!

    package com.eric.pickupjoke.activity; import java.io.IOException; import java.io.InputStream; import ...

  10. MySQL数据库

    1.1 数据库的发展史 1.1.1 萌芽阶段--文件系统 文件系统 1.1.2 第一代数据库--层次模型.网状模型 1.1.2.1层次模型 这是一种导航结构,导航结构的优点:分类管理:导航结构的缺点: ...