zoukankan      html  css  js  c++  java
  • 线程基础知识03-volatile和synchronized

    参考书:《Java并发编程艺术》

    在学习这一块知识之前,可以先学习一下JMM相关的知识,回过来再看这个问题,就很好理解:https://www.cnblogs.com/perferect/p/13680158.html

    volatile

    特性

    • 可见性:对一个volatile变量的读,总能看到任意线程对这个volatile变量最后的写入。

    • 原子性:对于一个volatile修饰的变量的读/写具有原子性,但是类似于volatile++ 这种复合操作不具有原子性

    注意:很多博客都写volatile变量不具有原子性,这是他们对上面原子性这段话产生了错误的理解

    举个例子

    volatile  int a = 0;
    
    上面也就是说:
    
    如果只是 a =10; 这种写入操作时没有问题的;
    
    但是 a = a  + a * 10 + 1 ; 这种同时进行读和写的操作时无法保证对volatile变量操作的原子性的;
    
    

    至于什么原因?

    • 其实我们在学JMM的时候,也知道了,在volatile的读和写之前进行的时不同的屏障,而这种复合操作,显然是很多个步骤的读和写,需要进行“区域管理”,这也就是下面我们要了解的synchronized要做的事情了

    volatile的原理

    编译器重排序的顺序一致性约束

    • 正如我们前面学习到的JMM中,编译器重排序,通过对volatile变量,读和写增加内存屏障来约束

    转成可执行代码后的缓存一致性

    • 通过Lock前缀,引起处理器缓存回写到内存
    其实指是通过#LOCK指令锁定内存中的缓存并写回到内存区,并使用缓存一致性机制来保证修改的原子性。此操作被称为“缓存锁定”,缓存一致性机制会阻止同时修改有两个以上处理器缓存的内存区间。
    
    • 利用嗅探技术,保证一个处理器的缓存回写到内存中其他处理器的缓存会变成无效。

    synchronized

    • JMM编译器重排序

      • 锁通过创建临界域,限制域外的代码和域内部代码的重排序,避免临界域内的变量“逸出”域。
    • 生成指令执行过程中

      • 底层是通过在方法的插入点通过monitorenter和monitorexit进行匹配。

    synchronized中的锁:

    • 对于普通同步方法,锁是当前实例对象。

    • 对于静态同步方法,锁是当前类的Class对象

    • 对于同步方法快,锁是Synchonized括号里配置的对象

    总结

    1. volatile和synchronized的区别

    • JMM编译器重排不同:

      • volatile:是通过在volatile变量的独写操作前后增加屏障实现防止重排序的

      • synchronized: 是通过增加临界区,防止临界区内变量逸出。

    • 执行指令的不同:

      • volatile:通过#LOCK前缀,刷新数据到主内存中

      • synchronized:是通过monitor,对指令块进行监听,通过monitorenter和monitorexit进行匹配

  • 相关阅读:
    DB2高可用hadr搭建参数配置
    redis一主两从搭建
    hdu 1064 Financial Management(超级大水题)
    hdu 1009 FatMouse' Trade(贪心水题)
    文件选择性加密解密
    uva 10405 Longest Common Subsequence(最长公共子序列)
    UVa 111 History Grading (最长公共子序列)
    hdu 2550 百步穿杨(大水题)
    UVa 10066 The Twin Towers(LCS水题)
    ASP.NET学习参考站点
  • 原文地址:https://www.cnblogs.com/perferect/p/13679249.html
Copyright © 2011-2022 走看看