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

本文探讨了并发编程中的竞态条件问题,通过具体示例解析了竞态条件产生的原因及过程,并揭示了临界区的概念。文章还深入讨论了操作系统架构下内存与寄存器交互对竞态条件的影响。

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

介绍

当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竟态条件发生的代码称作临界区。

备注:以下这段代码就存在竞态条件,其中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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值