inspur007 2011-08-17 13:10
浏览 221
已采纳

Java关键字 final,真的有这么神奇的作用嘛?

[url]http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#finalRight[/url]
这是 JSR-133 关于 final 的说明。其中,第一个例子 FinalFieldExample 如下:
[code="java"]
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;

public FinalFieldExample() {
    x = 3;
    y = 4;
}

static void writer() {
    f = new FinalFieldExample();
}

static void reader() {
    if (f != null) {
        int i = f.x;
        int j = f.y;
    }
}

}
[/code]

然后,作者解释说
1、执行reader的线程[b]保证可以看到f.x为3[/b],因为x定义为final;
2、[b]不保证f.y为4[/b],因为f.y[color=red][b]未[/b][/color]定义为 final

但是,真的是这样吗?为什么 f.y有可能不为4能,难道就是因为 “调用writer()的线程 thread-locally cache了 y 的值,从而导致其他线程看不到y的值”
我写个测试程序,无论如何也无法得到f.y不为4的情况
[code="java"]
public class FinalFieldExample {
final int x;
int y;

static FinalFieldExample f;

public FinalFieldExample() {
    x = 3;
    y = 4;
}

static void writer() {
    f = new FinalFieldExample();
}

static void reader() {
    while (f != null) {
        int i = f.x;
        int j = f.y;

        if (j != 4) {
            System.out.println("j should be 4");
        }

        if (i != 3) {
            System.out.println("i should be 3");
        }
    }
}

public static void main(String[] args) {
    class WriteThread extends Thread {
        public void run() {
            FinalFieldExample.writer();
        }
    }
    class ReadThread extends Thread {
        public void run() {
            FinalFieldExample.reader();
        }
    }
    new WriteThread().start();
    for (int i = 0; i < 100; i++) {
        new ReadThread().start();
    }
}

}
[/code]

也就是理论上存在这种可能吧。现实中,谁能写个测试程序,使得我们可以看到 f.y不等于 4??

  • 写回答

2条回答 默认 最新

  • snake168 2011-08-20 12:58
    关注

    关于问题1,可能你没理解线程内缓存的意思吧,1,2,3过程其实跟线程内缓存是有联系的,两者并不冲突

    比如说,将a变量赋值,当B线程需要读取a时,会将a的值从主存拷贝到你所说的cache中去,其实就是cpu的寄存器,如果改变了a的值,只是改变了寄存器的值,是不保证会写回主存的,所以对C线程是不可见的

    1,2,3步骤说的是另一码事,是说构造器的一个实现逻辑,与cache其实并没有太大的关系

    而final关键字,或者是是否值会改变,其实更重要的是构造器的实现逻辑

    第二个问题,我也写了点代码尝试了一下,也无法出现想要的结果
    其实原因也很简单,并发量不够,而且这个是由于jvm优化,产生的偶然性几率极小的问题,所以难以重现是正常的

    学习并发的东西没必要太执着,知道原理就可以了,如果每个问题都想重现一下,那会累死去

    至于证据,我想了想,可以引用jsr133 faq里面的内容
    :在1.4以前,final并不保证在构造器中的并发安全,所以string会出现这样的情况,本来是"abc"的,结果读的时候却是另一个
    这个问题明显是很严重的bug,
    但是用1.3的人有多少人发现了这个bug?当时还不是用得好好的

    以此来推出这个问题难以复现,应该是成立的

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建