• volatile关键字 学习记录2


     1 public class VolatileTest2 implements Runnable{
     2     volatile int resource = 0;
     3     
     4     public static void main(String[] args) {
     5         VolatileTest2 vt = new VolatileTest2();
     6         new Thread(vt).start();
     7         new Thread(vt).start();
     8         while(Thread.activeCount() > 1){
     9             Thread.yield();
    10         }
    11         System.out.println(vt.resource);
    12     }
    13 
    14     @Override
    15     public void run() {
    16         for(int i=0; i<100000000; i++){
    17             resource++;
    18         }
    19     }
    20 }

    这个例子中虽然resource前面有volatile关键字,但是运行结果有时候仍然不是200000000..为什么呢? 我想分享下我的观点.

    首先每个线程有自己的内存,他们修改resource的时候会先把数据拷贝到自己的内存中,再修改,再写回主内存..所以如果是这样的话那么多个线程同时操作可能会有很多种情况,下面举2种情况

    (不加volatile关键字的时候会出现的N种情况中的2种)

    第一种情况:

    第二种情况

    上面2种情况都会使t2线程把resource写回主内存的时候把t1自增那次操作覆盖掉.因为t1与t2线程读主内存的resource的值是一样的...所以相当于t1的自增是无效的.

    当resource前面加了volatile关键字的时候:

    用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。

    http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

    所以加了这个关键字以后是可以避免第二种情况的.

    t1 resource自增以后会直接写回主内存,使t2读取操作读取到的是最新的值.相当于resource++与写回主内存是同一个事务,不可以分隔.

    但是仍然不能避免第一种情况的发生.

    在第一种情况下,线程t2 读取resource是发生在t1 resource自增之前的,所以当t1 自增以后并不会影响t2线程内存中的resource,因为这并不违背volatile.如果此时t2再去读取resource那才是最新的值.不过可惜他在t1自增之前就读取了,所以t2中resource的值仍然是旧的.当t2写回主内存的时候仍然会覆盖t1自增的值.

    以上就是我的理解.

  • 相关阅读:
    重温MVC基础入门
    重温ASP.NET WebAPI(一)初阶
    WebApi的安全性及其解决方案
    Asp.net Core + EF Core + Bootstrap搭建的MVC后台通用管理系统模板(跨平台版本)
    ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统
    一款MVC5+EF+Bootstrap搭建的后台通用管理系统模板
    mac设置多个屏幕显示的问题
    JavaScript有这几种测试
    Script error.解决方法
    Script error.深度测试
  • 原文地址:https://www.cnblogs.com/abcwt112/p/5150470.html
Copyright © 2020-2023  润新知