美文网首页
(并发一)浅谈并发的数据竞争(可见性)与竞态条件(原子性)

(并发一)浅谈并发的数据竞争(可见性)与竞态条件(原子性)

作者: _____Mori_ | 来源:发表于2018-07-30 17:56 被阅读0次

其实并发比较根源的原因就是操作的原子性和状态的可见性无法保证

个人理解:

    1. 数据竞争?指的是并发条件下,状态属性信息不同步,产生读写误差。之所以会有误差,请参考JVM线程和堆的变量副本问题(缓存)。
    2. 竞态条件?指的是并发复合操作,结果不可预测问题。两者容易混淆


数据竞争,竞态条件.png

/**
 * Created by mori.wang on 2018/7/30.
 * 经典数据竞争:成员变量不用volatile 关键字,无法保证成员最终状态能被正确读到
 * */
public class DataRace {
    private long count;
    private volatile long countSafe;
    public void set(long newCount){
        count=newCount;
    }
    public void setSafe(long newCount){
        countSafe=newCount;
    }

    public long get(){
        return count;//
        /**
         * A thread:dataRace.set
         * B thread:dataRace.get
         *          此时出现数据竞争
         *          线程内各自有缓存数据 没同步到共享内存
         *          本应获得A线程更新后的值 却依旧获得旧的值
         *          此时方法语义不明确,可能造成线程不安全
         *          不一定会出现竞态条件,看线程执行顺序和运气以及调用语义*
         */
    }

    public long getCountSafe(){

        return countSafe;
        /**
         * 
         * 保证countSafe在线程间可见
         *
         */
    }
}
package concurrentExample.cas;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by mori.wang on 2018/7/30.
 * 经典竞态条件:复合操作 自增
 * */
public class RaceCondition {
    private Long count;
    private AtomicLong countSafe;
    private void increase(){
        /**
         * get count
         * set count+1
         * 复合操作
         * 既存在数据竞争 get的时候可能另外一个set了
         * 也存在竞态条件 操作结果不可预测(针对该方法
         */
        count++;
    }
    private void increaseSafe(){
        /**
         * 安全可靠 cas 
         */
        countSafe.addAndGet(1);

    }
}
典型并发问题:先检查后执行

——摘自JAVA并发编程实战
在实际情况中经常会遇到竞态条件*例如,假定你计划中午在University Avenue的星巴克与一位朋友会面。但当你到达那里时,发现在University Avenue上有两家星巴克,并且你不知道是哪一家。在12:00时,你没有在星巴克A看到朋友,那么就会去星巴B看看他是否在那里但他也不在那里。这有几种可能:你的朋友迟到了,还没到仵何一家星巴克;你的朋友在你离开后到星巴克A ; 你的朋友在星巴克B,但他去星巴克A找你,并且 此时正在去星巴克A的途中。假设是最糟糕的情况,即最后一种可能.现在是你们两个都去过了两家星巴究,且开始怀疑对方是否失约了.现在你会怎么做? 到另一家 星巴克?来来回回要走名少次?除非你们之间约定了其种协议,否则你们整天都在University Avenue上走来走去,倍感沮丧。在“我去看看他是否在另一家星巴克”这种方法中,问题在于:当你在街上走时,你的朋 友可能已经离开了你要去的星巴克。你首先看看星巴克A,发现“他不在”,并且开始去找他。你可以在星巴克B屮做同样的选择,但不是同时发生。两家星巴克之间有几分钟的路程, 而就在这几分钟的时间里,系统的状态可能会发生变化。
在星巴克这个示例中说明了一种竞态条件.因为要获得正确的结果(与朋友会面),必须 取决于亊件的发生时序(当你们到达星巴克时,在离开并去另一家星巴克之前会等待多长时 间……)。当你迈出前门时,你在星巴克A的观察结果将变得无效,你的朋友可能从后门进来 了,而你却不知道。这种观察结果的失效就是大多数竞态条件的本质一于一种可能失效的 观察结果来做出判断或者执行某个计算。这种类型的竞态条件称为“先检査后执行”:首先观 察到某个条件为真(例如文件X不存在)•然后根据这个观察结果采用相应的动作(创建文件 X),但事实上,在你观察到这个结果以及开始创建文件之间,观察结果可能变得无效(另一 个线程在这期间创建了文件X),从而导致各种问题(未预期的异常、数据被覆盖、文件被破坏等)。

引出实际遇到的坑:存在状态的数据竞争,也存在并发下的竞态条件
  1. 历史坑


    ExecutorService es = Executors.newFixedThreadPool(4);无法保证FIFO导致交叉执行产生并发问题

偷偷吐槽下 看代码还是比较花时间的。虽然解决起来不难,复现溯源难。解决方案:改用FIFO的线程池或者去掉定时任务1(感觉这个任务1很鸡肋,删行不删头,而且任务23都会覆盖数据的,不需要专门做个任务去删)

  1. 自造坑:
    两台机器同时进行操作,恰好同时检查数据库中不存在记录,都走入插入数据的流程


解决方案:


利用redis实现个分布式锁
END

理解了基本并发问题所在,可以尝试接着了解解决并发问题同时带来的性能损耗问题。了解更多并发的奥秘。一起看书吧~博客的知识点零零碎碎,书本才能带来系统化结构化的知识体系。(锁的实现,性能的损耗,分布式问题,JDK5并发包的奥秘)

相关文章

  • (并发一)浅谈并发的数据竞争(可见性)与竞态条件(原子性)

    其实并发比较根源的原因就是操作的原子性和状态的可见性无法保证 个人理解:     1. 数据竞争?指的是并发条件下...

  • Java高并发--原子性可见性有序性

    Java高并发--原子性可见性有序性 主要是学习慕课网实战视频《Java并发编程入门与高并发面试》的笔记 原子性:...

  • java并发编程要点

    Java并发问题主要有三个核心概念:原子性,可见性,顺序性。 原子性 并发问题的原子性的概念和数据库事务的原子性是...

  • 并发专题目录贴

    并发一、并发一:JAVA并发模型 并发二、原子性、有序性、可见性 并发三、同步原语final、volatile的内...

  • Volatile关键字从理解到实操,源码实例深度剖析

    谈到并发编程 ,必知晓并发三要素 :原子性、可见性、有序性。而 Volatile 涉及了可见性与有序性,是轻量级的...

  • volatile关键字

    并发编程 并发编程三个特性: 1:原子性:synchronized 可以保证代码片段的原子性。 2:可见性:如果一...

  • 并发编程总结

    并发概念 并发变成三大特性 原子性 可见性 有序性 区分数据库事务四大特性:原子性、一致性、隔离性、持久性 线程的...

  • 原子性,可见性,有序性

    转载自:并发之可见性并发之原子性并发之有序性 01 可见性的阐述 可见性 的定义是:一个线程对共享变量的修改,另外...

  • Java并发编程基础

    Java并发程序的设计 并发的三大特性:原子性,可见性和有序性。 原子性 原子性指的是一个操作一旦开始就不可中断。...

  • 【漫画】JAVA并发编程 如何解决原子性问题

    在并发编程BUG源头文章中,我们初识了并发编程的三个bug源头:可见性、原子性、有序性。在如何解决可见性和原子性文...

网友评论

      本文标题:(并发一)浅谈并发的数据竞争(可见性)与竞态条件(原子性)

      本文链接:https://www.haomeiwen.com/subject/uhufvftx.html