Java并发编程(一)---原子性,可见性,有序性

摘要

并发编程世界里,由于CPU缓存导致的可见性问题,线程切换导致的原子性问题,以及编译器重排序导致的有序性问题是并发编程Bug的根源。
正文
可见性

一个线程对共享变量的修改。另外一个线程能够立刻看到,我们称之为可见性。共享变量指的是存放在堆内存,由所有线程所共享的变量。比如:实例变量,静态变量。
如图所示:
在这里插入图片描述

共享变量V可以由线程A和线程B同时操作,线程A和B首先从各自的CPU缓存或者寄存器中读取数值,然后由CPU的寄存器写入内存中。

public class LongTest {
private static long atest = 0L;
public void countTest() {
for (int i = 0; i < 10000; i++) {
atest = atest + 1;
}
}
public static void main(String[] args) throws InterruptedException {
final LongTest longTest = new LongTest();
Thread threadA = new Thread(new Runnable() {
public void run() {
longTest.countTest();
}
});
Thread threadB = new Thread(new Runnable() {
public void run() {
longTest.countTest();
}
});
threadA.start();
threadB.start();
threadA.join();
threadB.join();
System.out.println("*******获得到的atest值为=" + atest);
}
}

如上程序,运行之后我们会发现 atest 值永远都不会到达20000,而是在10000-20000之间的随机数。
原因分析:假设线程A和线程B同时执行 atest = atest + 1;, 线程A 读取到的原值是0,执行+1操作之后,得到新值1,同样的,线程B也是读取到的原值0,然后执行+1操作,得到新值1。这样就永远得不到结果2。
类推的话,循环执行10000次也是同理,线程A执行+1操作时不能及时获得线程B已经写入的值,故导致值永远不可能达到20000。
原子性

由于一条高级语句在CPU中可能会分成若干条指令来执行,每条指令执行完之后就有可能会发生线程切换。故线程切换造成的原子性问题。

例如: count=count+1 共有三个指令

指令一: 将count值从内存加载到到CPU的寄存器中
指令二:在寄存器中+1操作
指令三 :将新值写入到内存中(由于缓存机制,写入的可能是CPU的缓存而不是内存)

操作系统做任务切换可以发生在任何一条CPU指令执行完,是CPU指令执行完。
我们将一个或者多个操作在CPU执行过程中不被中断的特性称之为原子性。
有序性

编译器重排序导致的有序性问题:
例如:双重加锁中的:

public class SingletonDemo {
private static SingletonDemo instance = null;

private SingletonDemo(){

}

static SingletonDemo getSingletonDemo() {
    if (instance == null) {
        synchronized (SingletonDemo.class) {
            if (instance == null) {
                instance = new SingletonDemo();    //6
            }
        }
    }
    return instance;
}

。。。。。。。。。。。。。。。。。

版权原因,完整文章,请参考如下:Java并发编程(一)---原子性,可见性,有序性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值