Java多线程之内存可见性和原子性:Synchronized和Volatile的比较

    【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/52525724
 

在说明Java多线程内存可见性之前,先来简单了解一下Java内存模型。

     (1)Java所有变量都存储在主内存中
     (2)每个线程都有自己独立的工作内存,里面保存该线程的使用到的变量副本(该副本就是主内存中该变量的一份拷贝)
   (1)线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接在主内存中读写
   (2)不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。
线程1对共享变量的修改,要想被线程2及时看到,必须经过如下2个过程:
   (1)把工作内存1中更新过的共享变量刷新到主内存中
   (2)将主内存中最新的共享变量的值更新到工作内存2中
可见性与原子性
   可见性:一个线程对共享变量的修改,更够及时的被其他线程看到
   原子性:即不可再分了,不能分为多步操作。比如赋值或者return。比如"a = 1;"和 "return a;"这样的操作都具有原子性。类似"a += b"这样的操作不具有原子性,在某些JVM中"a += b"可能要经过这样三个步骤:
① 取出a和b
② 计算a+b
③ 将计算结果写入内存
 
(1)Synchronized:保证可见性和原子性
    Synchronized能够实现原子性和可见性;在Java内存模型中,synchronized规定,线程在加锁时,先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁。
(2)Volatile:保证可见性,但不保证操作的原子性
    Volatile实现内存可见性是通过store和load指令完成的;也就是对volatile变量执行写操作时,会在写操作后加入一条store指令,即强迫线程将最新的值刷新到主内存中;而在读操作时,会加入一条load指令,即强迫从主内存中读入变量的值。但volatile不保证volatile变量的原子性,例如:

  1. Private int Num=0;
  2. Num++;//Num不是原子操作

Num不是原子操作,因为其可以分为:读取Num的值,将Num的值+1,写入最新的Num的值。
    对于Num++;操作,线程1和线程2都执行一次,最后输出Num的值可能是:1或者2
   【解释】输出结果1的解释:当线程1执行Num++;语句时,先是读入Num的值为0,倘若此时让出CPU执行权,线程获得执行,线程2会重新从主内存中,读入Num的值还是0,然后线程2执行+1操作,最后把Num=1刷新到主内存中; 线程2执行完后,线程1由开始执行,但之前已经读取的Num的值0,所以它还是在0的基础上执行+1操作,也就是还是等于1,并刷新到主内存中。所以最终的结果是1

    一般在多线程中使用volatile变量,为了安全,对变量的写入操作不能依赖当前变量的值:如Num++或者Num=Num*5这些操作。
(3)Synchronized和Volatile的比较
    1)Synchronized保证内存可见性和操作的原子性
    2)Volatile只能保证内存可见性
    3)Volatile不需要加锁,比Synchronized更轻量级,并不会阻塞线程(volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。)
    4)volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化(如编译器重排序的优化).
    5)volatile是变量修饰符,仅能用于变量,而synchronized是一个方法或块的修饰符。
      volatile本质是在告诉JVM当前变量在寄存器中的值是不确定的,使用前,需要先从主存中读取,因此可以实现可见性。而对n=n+1,n++等操作时,volatile关键字将失效,不能起到像synchronized一样的线程同步(原子性)的效果。
 
【相关习题】
(1)下列说法不正确的是()
A.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
B.当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
C.当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问不会被阻塞。
D.当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
答案:C,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将会被阻塞。
(2)下面叙述错误的是:
A.通过synchronized和volatile都可以实现可见性
B.不同线程之间可以直接访问其他线程工作内存中的变量
C.线程对共享变量的所有操作都必须在自己的工作内存中进行
D.所有的变量都存储在主内存中
答案:B,不同线程之间无法直接访问其他线程工作内存中的变量

Java多线程之内存可见性和原子性:Synchronized和Volatile的比较的更多相关文章

  1. 细说Java多线程之内存可见性

    编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用)         1.共享变量在线程间的可见性                共享变量:如果一个 ...

  2. 细说Java多线程之内存可见性笔记

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 说明:多线程的内存可见性涉及到多线程间的数据争用,也涉及到了多线程间的数据可见性 一.共享变量在线程间的 ...

  3. java多线程之内存可见性-synchronized、volatile

    1.JMM:Java Memory Model(Java内存模型) 关于synchronized的两条规定: 1.线程解锁前,必须把共享变量的最新值刷新到主内存中 2.线程加锁时,将清空工作内存中共享 ...

  4. Java多线程之内存可见性

    阅读本文约“3分钟” 共享变量在线程间的可见性 synchronized实现可见性 volatile实现可见性 —指令重排序 —as-if-serial语义 —volatile使用注意事项 synch ...

  5. Java多线程之可见性与原子性——synchronized VS volatile

    <转:http://blog.csdn.net/uniquewonderq/article/details/48113071> 程序举例: 代码: package com.synch; p ...

  6. java多线程03-----------------volatile内存语义

    java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...

  7. Java线程工作内存与主内存变量交换过程及volatile关键字理解

    Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模 ...

  8. 1 Java线程的内存可见性

    Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...

  9. God 1.1.1 多线程之内存可见性

    共享变量在线程间的可见性 synchronize实现可见性 volatile实现可见性 指令重排序 as-if-serial语义 volatile使用注意事项 synchronized和volatil ...

随机推荐

  1. CAS机制

    ##################################################################### 我们知道多线程操作共享资源时,会出现三个问题:可见性.有序性 ...

  2. 匹克定理pick

    与POJ1226为例 要知道在一个格点多边形内 知道期内部的点数 Q,边上的点数L,就可以知道他的面积pick定理及 S=Q+L/2-1; 然后 还有边上的点数除了多边形的顶点外,还有一些点该怎么求呢 ...

  3. Intro to Python for Data Science Learning 4 - Methods

    Methods From:https://campus.datacamp.com/courses/intro-to-python-for-data-science/chapter-3-function ...

  4. Zookeeper使用实例——服务节点管理

    分布式处理中,总会存在多个服务节点同时工作,并且节点数量会随着网络规模的变化而动态增减,服务节点也有可能发生宕机与恢复.面对着动态增减的服务节点,我们如何保证客户请求被服务器正确处理呢.我们可以通过z ...

  5. ThinkPHP CURD mysql操作

    ThinkPHP CURD操作 ThinkPHP提供了灵活和方便的数据操作方法,对数据库操作的四个基本操作(CURD):创建.更新.读取和删除的实现是最基本的,也是必须掌握的,在这基础之上才能熟悉更多 ...

  6. 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持

    前言 距离上一篇文章<基于EF Core的Code First模式的DotNetCore快速开发框架>已过去大半个年头,时光荏苒,岁月如梭...比较尴尬的是,在这大半个年头里,除了日常带娃 ...

  7. SQL学习之MYSQL的常用命令和增删改查语句和数据类型

    连接命令:mysql -h[主机地址] -u[用户名] -p[用户密码] 创建数据库:create database [库名] 显示所有数据库: show databases; 打开数据库:use [ ...

  8. AJAX 与 Python 后台通信

    Ajax 简介 Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术. Ajax = 异步 ...

  9. 20145206邹京儒 Exp8 Web基础

    20145206邹京儒 Exp8 Web基础 一.实践过程记录 Apache (一)环境配置 1.查看端口占用:在这里apach2占用端口80 2.测试apache是否正常工作:在kali的火狐浏览器 ...

  10. 一款简单实用的jQuery图片画廊插件

    图片画廊 今天分享一个自己实现的jQuery 图片画廊插件. 看一下效果图: 点击图片时: 在线演示地址:http://www.jr93.top/photoGallery/photoGallery.h ...