原子操作是不能被线程集中中断的操作。

原子性可以应用于除long和double之外的素有基本类型,jvm将64位的读取和写入当做两个分离的32位操作来执行,产生一个读取和写入操作中间发生上下文切换,导致不同人物可以看到不正确结果的可能性。

volatile关键字还确保了应用中的可视性,如果将一个域声明为volatile的,那么只要对这个域产生了写操作,所有的读曹组就都可以看到这个修改。如果一个域完全有synchronize方法或语句块来防护,就不必将其设置为volatile。

当一个域的值依赖于它之前的值时,volatile就无法工作了。如果某个域内部受到其他域的值的影响,那么volatile也无法工作,例如Range类的lower和upper边界就必须遵循lower<upper的限制。

使用volatile而不是synchronize的唯一安全的情况是类中只有一个可变的域。

原子操作,对域中的值的赋值和返回都是原子性的对于c++,但是对于java不是。

如果一个域可能会被多个任务同时访问时,或者这些任务中至少有一个是写入任务,那么久应该将这个域设置为volatile,如果将一个域定义为volatile,那么它就会告诉编译器不要执行任何一次读取和写入操作的优化。

原子类:

AtomicInteger  AtomicLong AtomicReference

在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。

Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制。

synchronized

同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用

synchronized 修饰的方法 或者 代码块。

volatile

用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。

下面看一个例子,我们实现一个计数器,每次线程启动的时候,会调用计数器inc方法,对计数器进行加一

执行环境——jdk版本:jdk1.6.0_31 ,内存 :3G   cpu:x86 2.4G

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Counter {
    public static int count = 0;
    public static void inc() {
        //这里延迟1毫秒,使得结果明显
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
        }
        count++;
    }
    public static void main(String[] args) {
        //同时启动1000个线程,去进行i++计算,看看实际结果
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                }
            }).start();
        }
        //这里每次运行的值都有可能不同,可能为1000
        System.out.println("运行结果:Counter.count=" + Counter.count);
    }
}

1
  
1
运行结果:Counter.count=995
1
实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count=995,可以看出,在多线程的环境下,Counter.count并没有期望结果是1000
1
  
1
很多人以为,这个是多线程并发问题,只需要在变量count之前加上volatile就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Counter {
    public volatile static int count = 0;
    public static void inc() {
        //这里延迟1毫秒,使得结果明显
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
        }
        count++;
    }
    public static void main(String[] args) {
        //同时启动1000个线程,去进行i++计算,看看实际结果
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                }
            }).start();
        }
        //这里每次运行的值都有可能不同,可能为1000
        System.out.println("运行结果:Counter.count=" + Counter.count);
    }
}

运行结果:Counter.count=992

运行结果还是没有我们期望的1000,下面我们分析一下原因

在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,

线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存

变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,

在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图

描述这写交互

read and load 从主存复制变量到当前工作内存
use and assign  执行代码,改变共享变量值 
store and write 用工作内存数据刷新主存相关内容

其中use and assign 可以多次出现

但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样

对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的

例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值

在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6

线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6

导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。

<p http:="" www.cnblogs.com="" aigongsi="" "="" target="_blank" style="margin-top: 12px; margin-bottom: 0px; padding: 10px; border: 1px dashed rgb(224, 224, 224); background: rgb(230, 230, 230);">GodIsCoder 
博客园blog地址:http://www.cnblogs.com/aigongsi/ 
独立Blog:God Is Coder 
个人网站:iphone发码网 
本人版权归作者和博客园所有,欢迎转载,转载请注明出处

21.3.3 原子性与易变性 21.3.4 原子类相关推荐

  1. java 并发原子性与易变性 来自thinking in java4 21.3.3

    java 并发原子性与易变性  具体介绍请參阅thinking in java4 21.3.3 thinking in java 4免费下载:http://download.csdn.net/deta ...

  2. 鸣礼炮21响的含义c语言,健身21响礼炮什么意思?怎么做?一次适合练几组? 21响礼炮做法详解...

    在之前小编给大家介绍了21响礼炮的前身'一个半'训练法.这个训练方法当然很不错,但是它的进阶版,也就是我们今天要介绍的21响礼炮,那才是真正的力竭神器!大家首次接触到这个高级训练法则应该是在阿诺德施瓦 ...

  3. java 原子类_小学妹教你并发编程的三大特性:原子性、可见性、有序性

    在并发编程中有三个非常重要的特性:原子性.有序性,.可见性,学妹发现你对它们不是很了解,她很着急,因为理解这三个特性对于能够正确地开发高并发程序有很大的帮助,接下来的面试中也极有可能被问到,小学妹就忍 ...

  4. atomic原子类实现机制_JDK中Atomic开头的原子类实现原子性的原理是什么?

    JDK Atomic开头的类,是通过 CAS 原理解决并发情况下原子性问题. CAS 包含 3 个参数,CAS(V, E, N).V 表示需要更新的变量,E 表示变量当前期望值,N 表示更新为的值.只 ...

  5. 原子性概念及原子类的工作原理-CAS机制

    1.原子性概念 原子性是指一个操作是不可中断的,要么全部执行成功,要么全部执行失败,有着"同生共死"的感觉.即使在多个线程一起执行的时候,一个操作一旦开始,就不会被其它的线程干扰. ...

  6. 【SSH网上商城项目实战21】从Demo中看易宝支付的流程

    这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后,再做实际的开发,因为是一个Demo,所以我没有考虑一些设计模式的东西,就是直接实现支付功能.实现支付功能需要易宝给我们提供的AP ...

  7. mysql5.5.21安装图解_Windows系统安装MySQL5.5.21图解教程

    大家都知道MySQL是一款中.小型关系型数据库管理系统,很具有实用性,对于我们学习很多技术都有帮助 数据库是5.5.21这个版本的.以下是安装步骤: 1.首先单击MySQL5.5.21的安装文件,出现 ...

  8. 用python编21点游戏_【Python3】21点游戏

    刚开始学python,试着写了一个21点游戏. 游戏过程就是,一开始给你和庄家(就是电脑啦)各发两张牌,但庄家有一张是暗牌.接下来你可以选择是要牌(hit me)还是停止发牌直接开(stand),要牌 ...

  9. mysql安装教程8.0.21安装,Windows系统下MySQL8.0.21安装教程(图文详解)

    安装建议:尽量不要用.exe进行安装,用压缩包安装,对日后的卸载/版本升级更为方便 下载地址:https://dev.mysql.com/downloads/mysql/ 1.点击上面的下载地址得到z ...

最新文章

  1. git 在拉取代码的时候connect 谷歌报错_工具 | 手把手教你在VSCode中使用Git
  2. 解决服务器上安装不了centos7.4的问题
  3. java登录界面命令_Java命令行界面(第16部分):JArgp
  4. 毕业十年|我的嵌入式AI学习路线(笔记、代码)
  5. HTML中文编辑器 v1.31
  6. 用Canvas为网页加入动态背景
  7. python 编码解码原理_Python的编码解码问题
  8. python使用默认参数
  9. JavaScript中的数字型
  10. spring - ioc和aop
  11. usb摄像头做教学直播实现pc和手机都可以在线观看教程
  12. python中if brthon环境安装包_python-debian/test.deb.uu at master · romlok/python-debian · GitHub...
  13. Dzz1.3测试,增加IM、桌面协作、多选等。修缮问题后发布下载
  14. 鲁迅吃鱼肝油都不忘战斗
  15. 系统信息:uname,sysinfo,gethostname,sysconf
  16. 【求职】瓜子二手车 Java 方向面经
  17. 现在转行做程序员还有必要吗,培训班有必要去吗?
  18. 移动硬盘分区(以500G为例)
  19. java构建网页_从网页搭建入门Java Web2018版
  20. win10任务栏转圈圈解决方法

热门文章

  1. windows远程下载
  2. Hi Azure. 从零开始打造一个语音机器人,跟你的电脑聊聊天。
  3. 传阿里旗下蚂蚁集团拟上市集资300亿美元,最快9月IPO
  4. G6 图可视化引擎——快速上手
  5. Lake Counting POJ - 2386
  6. 《信息学奥赛一本通》 高精度加法。输入两个正整数,求它们的和。
  7. windows 下终止指定端口的进程
  8. 【机器视觉】 dev_close_tool算子
  9. 【Qt】简单QT文本编辑器
  10. mysql 慢查询 不重启_开启mysql慢查询日志,不重启数据库的方法