zoukankan      html  css  js  c++  java
  • 01-并发编程bug源头:可见性、原子性和有序性

    一、可见性

      是指多线程在不同cpu缓存(多核)中对同一个变量进行修改,导致的不可见

    二、原子性

      指线程间切换导致的原子性问题

      一条编程语句执行往往包含多条CPU指令,操作系统做任务切换,可以发生在任意一条cpu指令执行完

      比如count+=1;这条语句包含3条cpu指令:

      1.把变量count从内存中加载到cpu寄存器;

      2.在cpu寄存器中执行+1操作

      3.把结果写入内存(也可能是因为缓存机制写入的是cpu缓存而不是内存)

    三、有序性

     因为编译器优化导致程序语句的执行顺序发生变化。

    经典案例就是单例模式中利用双重检查创建单例对象。

     1 public class Singleton{

    3 private static Singleton instance; 4 5 private static Singleton getInstance(){ 6 7   if(instance==null){ 8 9     sychronized(Singleton.class){ 10 11       if(instance==null){ 12 13         instance=new Singleton(); 14 15       } 16 17     } 18 19   } 20 21   return instance; 22 23 } 24 25 }

    问题出在new操作上,我们以为的操作是这样的:

      1.分配一块内存M;

      2.在内存M上初始化Singleton对象

      3.将地址M赋值给变量instance

    而实际上经过编译优化的执行操作是这样的:

      1.分配一块内存M;

      2.将地址M赋值给变量instance

      3.在内存M上初始化Singleton对象

    解决办法:把属性Singleton instance加修饰符volatile就完美了,对instance进行volatile语义声明,就可以禁止指令重排序。

    四、关于volatile资料参考:https://www.jianshu.com/p/ccfe24b63d87
    volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略。
    volatile 的特性
    保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
    禁止进行指令重排序。(实现有序性)
    volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。

    五、关于cpu缓存、线程工作内存:https://blog.csdn.net/u013851082/article/details/70314778/

  • 相关阅读:
    「数列分块入门学习笔记」
    「Luogu P3273 [SCOI2011]棘手的操作」
    「CF1342D Multiple Testcases」
    「CF803G Periodic RMQ Problem」
    【cf比赛记录】Educational Codeforces Round 77 (Rated for Div. 2)
    【cf比赛记录】Codeforces Round #601 (Div. 2)
    【cf比赛记录】Codeforces Round #600 (Div. 2)
    【学习报告】简单搜索
    【POJ2676】Sudoku
    【POJ1416】Shredding Company
  • 原文地址:https://www.cnblogs.com/bbsh/p/11649454.html
Copyright © 2011-2022 走看看