并发编程五:竞态条件与临界区

    xiaoxiao2025-04-10  14

    并发编程:竞态条件与临界区

    介绍

    当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竟态条件发生的代码称作临界区。 备注:以下这段代码就存在竞态条件,其中return ++count就是临界区。
    public class Obj { private int count; public int incr() { return ++count; } }
    同一程序中运行在多个线程本身不会导致任何问题,问题在于当多个线程访问了相同资源时候。 如:访问同一内存区(变量、数组、对象)、数据库或文件。那么就可能会出现问题了。

    竞态条件分析

    演示代码

    public class Counter { private int count = 0; public int incr() { return (++count); //上面一句代码替换为下面的代码可能更好理解 int sum=count+1 return sum //首先++count并非是一个原子操作,其实先读取count值然后再自增操作的。 } }
    假如现在有A,B两个线程执行incr方法 T1时刻:A读取count值为0在执行自增操作之前,cpu又调度到B执行了 T2时刻:B读取count值为0执行自增操作count变为1,cpu又调度到A线程执行 T3时刻:A继续执行自增操作,count值变为1.此时就存在问题了,A线程没有重新读取count的值,导致结果不对
    JVM按照下面的顺序执行incr()方法 1、从内存获取this.count的值放到寄存器 2、将寄存器中的值加1 3、将寄存器的值写回到内存 如果A、B线程交错执行的情景可能就如下 A:读取this.count到一个寄存器X1(0) B:读取this.count到一个寄存器X2(0) B:将寄存器X2的值加1 B:回写寄存器X2(1)到内存,this.count现在就是1 A:将寄存器X1的值加1 A:回写寄存器值X1(1)到内存,this.count闲杂就是1 备注:这样就存在问题了,B线程已经自增过一次了,但是A线程并没有发现,导致它任然以为this.count为0的基础上自增。 因此如果没有采用合适的同步机制,线程间的交叉执行的情况就无法预料的。 备注:之所以存在这种问题,其实本质上市因为操作系统架构问题,任何操作都会经过内存再到寄存器, 正因为有内存这一环节导致有些时候数据并不及时被刷新,但是有内存的架构师必须的也是很有必要的。如果直接将数据放在寄存器操作的话那简直难以想象。

    总结

    多线程开发是最重要的事情是先分析清楚共享资源和共享对象,明白什么地方会存在安全隐患,这样才能更好的避免引起安全问题。

    参考

    1、http://tutorials.jenkov.com/java-concurrency/thread-safety.html

    转载请注明原文地址: https://ju.6miu.com/read-1297913.html
    最新回复(0)