java并发--用实例从内存角度分析volatile

引入
详细了解相关内容推荐对比阅读。
JVM内存模型:
https://blog.csdn.net/FortressBesieged/article/details/88066898
volatile:
https://www.cnblogs.com/dolphin0520/p/3920373.html
synchronized
https://www.cnblogs.com/lcplcpjava/p/6858135.html
lock
https://www.cnblogs.com/dolphin0520/p/3923167.html
https://www.cnblogs.com/shen-smile/p/5142292.html

volatile

场景:

有一个使用volatile修饰的变量 i = 10,此时有两个线程A,B共同对变量1进行“i++”操作。

public class Test {
    public volatile int inc = 0;
    public void increase() {
        inc++;
    }
    public static void main(String[] args) {
        final Test test = new Test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }
        while(Thread.activeCount()>1)  //保证前面的线程都执行完
            Thread.yield();
        System.out.println(test.inc);
    }
}

注:i++对于线程来说并不是原子操作,包括三个步骤:从主内存中将变量i拷贝到自己的缓存中,在寄存器中执行自增操作,将操作后的变量写入自己的缓存。
分析:
某时刻变量i=10位于主内存中,线程A将变量i拷贝到了自己的缓存中,此时还未执行自增操作,线程阻塞。
此时线程B将变量i=10拷贝到自己的缓存(此时线程A未对变量i完成修改,并未将修改后的变量写入主内存),此时的i=10,线程B执行自增操作,写入缓存后同步到了主内存,此时主内存的i值为11。
若此时线程A继续执行,由于“volatile保证了新值能够立即同步到主内存中,以及每次使用前立即从主存中刷新”,对于此时的线程执行i++操作过程来说,每次指的是三个步骤全部完成,才算一次完成。所以,对于线程A来说,继续执行自增操作时,此时的变量i仍然是10并不是线程B修改后的11。这样,两个线程对于一个变量都执行自增操作,变量只增加了一次,所以volatile并不能保证原子性。所以说,若想正确使用volatile,那么对volatile修饰的内容执行的操作一定是原子操作才可以,对比上述场景来说,就是线程A在获取到变量i时,在写回到主内存之前都不会被阻塞,这样当线程B获取值时就不会获取到未被线程A操作过程中的值,这也就是synchronized关键字实现的内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值