zoukankan      html  css  js  c++  java
  • 并发编程三要素:原子性,有序性,可见性

    并发编程三要素

    1. 原子性: 一个不可再被分割的颗粒。原子性指的是一个或多个操作要么全部执行成功要么全部执行失败。
    2. 有序性: 程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)
    3. 可见性: 一个县城对共享变量的修改,另一个线程能够立刻看到。

    一、原子性

    线程切换会带来原子性的问题

    int i = 1; // 原子操作
    i++; // 非原子操作,从主内存读取 i 到线程工作内存,进行 +1,再把 i 写到主内存。

    虽然读取和写入都是原子操作,但合起来就不属于原子操作,我们又叫这种为“复合操作”。

    我们可以用synchronized 或 Lock 来把这个复合操作“变成”原子操作。

    例子:

    //使用synchronized
    private synchronized void increase(){
       i++;
     }
    //使用Lock
    private int i = 0;
     Lock mLock = new ReentrantLock();
     
     private void increase() {
       mLock.lock();
       try {
         i++;
       } finally{
         mLock.unlock();
       }
     }

    这样我们就可以把这个一个方法看做一个整体,一个不可分割的整体。

    除此之前,我们还可以用java.util.concurrent.atomic里的原子变量类,可以确保所有对计数器状态访问的操作都是原子的。

    例子:

    AtomicInteger mAtomicInteger = new AtomicInteger(0);  
    private void increase(){
        mAtomicInteger.incrementAndGet();
    }

    二、可见性

    缓存导致可见性问题

    int v = 0;
    // 线程 A 执行
    v++; 
    // 线程 B 执行
    System.out.print("v=" + v);

    即使是在执行完线程里的 i++ 后再执行线程 B,线程 B 的输入结果也会有 2 个种情况,一个是 0 和1。

    因为 i++ 在线程 A(CPU-1)中做完了运算,并没有立刻更新到主内存当中,而线程B(CPU-2)就去主内存当中读取并打印,此时打印的就是 0。

    禁用缓存能保证可见性,volatile关键字可以禁用缓存

    synchronized和Lock能够保证可见性。

    资源搜索网站大全 https://www.renrenfan.com.cn

    三、有序性

    导致有序性的原因是编译优化

    我们都知道处理器为了拥有更好的运算效率,会自动优化、排序执行我们写的代码,但会确保执行结果不变。

    例子:

    int a = 0; // 语句 1
    int b = 0; // 语句 2
    i++; // 语句 3
    b++; // 语句 4

    这一段代码的执行顺序很有可能不是按上面的 1、2、3、4 来依次执行,因为 1 和 2 没有数据依赖,3 和 4 没有数据依赖, 2、1、4、3 这样来执行可以吗?完全没问题,处理器会自动帮我们排序。

    在单线程看来并没有什么问题,但在多线程则很容易出现问题。

    再来个例子:

    // 线程 1
    init();
    inited = true;
     
    // 线程 2
    while(inited){
        work();
    }

    init(); 与 inited = true; 并没有数据的依赖,在单线程看来,如果把两句的代码调换好像也不会出现问题。

    但此时处于一个多线程的环境,而处理器真的把这两句代码重新排序,那问题就出现了,若线程 1 先执行 inited = true; 此时,init() 并没有执行,线程 2 就已经开始调用 work() 方法,此时很可能造成一些奔溃或其他 BUG 的出现。

    synchronized和Lock能确保原子性,能让多线程执行代码的时候依次按顺序执行,自然就具有有序性。

    而volatile关键字也可以解决这个问题,volatile 关键字可以保证有序性,让处理器不会把这行代码进行优化排序。

  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/14047330.html
Copyright © 2011-2022 走看看