volatile是变量修饰符,而synchronized则作用于一段代码或方法;看如下三句get代码:

  1. int i1;              int geti1() {return i1;}
  2. volatile int i2;  int geti2() {return i2;}
  3. int i3;              synchronized int geti3() {return i3;}

  geti1()得到存储在当前线程中i1的数值。多个线程有多个i1变量拷贝,而且这些i1之间可以互不相同。换句话说,另一个线程可能已经改 变了它线程内的i1值,而这个值可以和当前线程中的i1值不相同。事实上,Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程 可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的i1值是1,线程1里的i1值 是2,线程2里的i1值是3——这在线程1和线程2都改变了它们各自的i1值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。
   而geti2()得到的是“主”内存区域的i2数值。用volatile修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经 volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的,volatile修饰的变量 存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。
  既然volatile关键字已经实现了线程间数据同步,又要 synchronized干什么呢?呵呵,它们之间有两点不同。首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监 视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“ 主”内存区域同步整个线程的内存。因此,执行geti3()方法做了如下几步:
1. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放)
2. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗])
3. 代码块被执行
4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值)
5. 线程释放监视this对象的对象锁
  因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。

更通俗的解释:

Volatile 字面的意思时易变的,不稳定的。在C#中也差不多可以这样理解。

编译器在优化代码时,可能会把经常用到的代码存在Cache里面,然后下一次调用就直接读取Cache而不是内存,这样就大大提高了效率。但是问题也随之而来了。

在多线程程序中,如果把一个变量放入Cache后,又有其他线程改变了变量的值,那么本线程是无法知道这个变化的。它可能会直接读Cache里的数据。但是很不幸,Cache里的数据已经过期了,读出来的是不合时宜的脏数据。这时就会出现bug。

用Volatile声明变量可以解决这个问题。用Volatile声明的变量就相当于告诉编译器,我不要把这个变量写Cache,因为这个变量是可能发生改变的。

volatile和synchronized的更多相关文章

  1. Thread 学习记录 <1> -- volatile和synchronized

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

  2. volatile与synchronized的区别

    1.锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility). 互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一 ...

  3. 从JAVA看C#中volatile和synchronized关键字的作用

    最近一直在想C#中 volatile关键字到底是用来干什么的?查了很多.NET的文章都是说用volatile修饰的变量可以让多线程同时修改,这是什么鬼... 然后查到了下面这篇JAVA中关于volat ...

  4. 关于volatile和synchronized

    这个可能是最好的对比volatile和synchronized作用的文章了.volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符.所以我们使用这两种关键字来指定三种简单的 ...

  5. Volatile和Synchronized对可见性和原子性的支持

    在学习并发编程的时候,遇见了volatile和synchronized关键字问题,volatile是可以保证可见性,但无法保证原子性,synchronized关键字由于其是加锁机制,肯定是可以保证原子 ...

  6. volatile 与 synchronized 区别

    在Java中,为了保证多线程读写数据时保证数据的一致性,可以采用两种方式: 同步 如用synchronized关键字,或者使用锁对象. volatile 使用volatile关键字用一句话概括vola ...

  7. 剑指Offer——线程同步volatile与synchronized详解

    (转)Java面试--线程同步volatile与synchronized详解 0. 前言 面试时很可能遇到这样一个问题:使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现 ...

  8. 并发编程之ThreadLocal、Volatile、synchronized、Atomic关键字扫盲

    前言 对于ThreadLocal.Volatile.synchronized.Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点.区别 ...

  9. java多线程中 volatile与synchronized的区别-阿里面试

    volatile 与 synchronized 的比较(阿里面试官问的问题) ①volatile轻量级,只能修饰变量.synchronized重量级,还可修饰方法 ②volatile只能保证数据的可见 ...

  10. volatile与synchronized有什么区别?

    下列说法正确的是()? A.我们直接调用Thread对象的run方法会报异常,所以我们应该使用start方法来开启一个线程 B.一个进程是一个独立的运行环境,可以被看做一个程序或者一个应用.而线程是在 ...

随机推荐

  1. 解决strcmp的错误以及VS的快捷键

    主要是C++数组作业中发现的一些问题. 第一点是关于strcat函数 我用VS2018调用strcat的时候报错,错误信息提示strcat不安全(?)要用strcat_s.修改后,可成功运行. 但这两 ...

  2. Itellj Idea使用技巧

    模板设置: 类模板:File–>Settings–>Editor–>File and Code Templates–>Includes–>File Header 输入缩写 ...

  3. 高性能迷你React框架anujs1.0.5发布

    实现对createFactory的支持,优化scheduler与dispose机制,提供ReactShim文件,跑通公司内部4套测试 npm i anujs 或者使用架手架 https://githu ...

  4. MySQL中IN子查询会导致无法使用索引

    今天看到一个博客园的一篇关于MySQL的IN子查询优化的案例,一开始感觉有点半信半疑(如果是换做在SQL Server中,这种情况是绝对不可能的,后面会做一个简单的测试.)随后动手按照他说的做了一个表 ...

  5. 26.Hibernate-主键和映射.md

    目录 1.复合主键映射 [toc] 2.集合映射 2.1Set集合 2.2其他集合 [toc] 3.集合数据的读取 [toc] 4.一对多和多对一映射 4.1概念 4.2配置和开发 4.2.1关键点 ...

  6. javascript正则表达式中 (?=exp)、(?<=exp)、(?!exp)

     (?=exp) 百度百科给的解释:非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用.例如,“Windows(?=95|98|NT|2000) ...

  7. 使用JS读取本地文本文件(兼容各种浏览器)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Python设计模式 - 基础 - 七大基本原则

    提倡使用设计模式,主要出发点就是实现代码复用,增加代码的扩展性和可维护性.如何设计出简洁.易懂.灵活.优美的代码结构的确是一门学问,透彻理解并践行如下七大原则通常都能取得基本满意的结果: - 单一职责 ...

  9. c++ 中的数字和字符串的转换

    理由:一直忘记数字型的字符串和数字之间的转换,这次总结一下,以便后面再次用到. 其实 C++ 已经给我们写好了相应的函数,直接拿来用即可 QA1:如何把一个数字转换为一个数字字符串?(这个不是很常用) ...

  10. elasticsearch 动态增加副本

    动态调整副本数 PUT /ptt-new-2018-11/_settings{ "number_of_replicas": 2} 重建索引, 增加节点后要重建索引. 日志报错为网络 ...