看《Java并发编程实战》遇到如下问题

代码:

/**
* Created by yesiming on 16/11/11.
*/
public class Holder {
private int n; public Holder(int n) {
this.n = n;
} public void assertSanity() {
if(n != n) {
throw new AssertionError("This statment is false.");
}
}
} 疑问是:assertSanity() 方法中的判断 n != n
n它怎么就能不等于n呢,它们是同一个变量呀 解惑:设想一下场景
有2个线程 A,B
A做的操作:Holder holder = new Holder(42);
B做的操作:
if(holder != null) {
  holder.assertSantiy();
}
对于线程A的操作,jvm执行时的步骤:1.栈里生成holder引用,2.执行构造函数,在堆里生成Holder的内存空间,并且给n赋值为42,3.把holder指向堆里生成的内存空间
问题是:上面的1,2,3步骤不是按照1,2,3的顺序执行的,执行引擎对指令重排序后,可能会按照1,3,2的顺序执行,也可能是别的顺序
结果:这样就导致当holder指向了堆里的内存空间时(这时holder不是null了),但是构造函数执行尚未完成,n还没有被赋值为42。 对于线程B的操作,assertSanity()方法编译后的指令如下:

public void assertSanity();
flags: ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field n:I
4: aload_0
5: getfield #2 // Field n:I
8: if_icmpeq 21
11: new #3 // class java/lang/AssertionError
14: dup
15: ldc #4 // String This statment is false.
17: invokespecial #5 // Method java/lang/AssertionError."<init>":(Ljava/lang/Object;)V
20: athrow
21: return
LineNumberTable:
line 14: 0
line 15: 11
line 17: 21
LocalVariableTable:
Start Length Slot Name Signature
0 22 0 this Lo1/Holder;
}

注意看绿色部分的指令,
第一步:1: getfield #2 // Field n:I
取得n的值
第二部:5: getfield #2 // Field n:I
取得n的值
也就是说,在执行比较指令if_icmpeq之前,要让比较的两个数都进栈,然后做比较
那么,既然要进栈2次,也就可以推导出,当线程B操作第一步getField时,n没有被线程A赋值,那么这个n是0,之后,线程A修改了n的值,第二次进栈时,n的值已经是修改后的42了
这样,就会导致栈顶2个slot中的数,一个0,一个是42,必然会导致8: if_icmpeq的结果为真 解决方案:
把n定义成final,并且在声明Holder时,使用valetile关键字
final能保证Holder在构造方法执行时,不会被执行引擎重排序,也就不会出现holder指向了Holder构造产生的内存空间,但是构造方法没有执行完成的情况(n没有被赋值)
valetile保证了在外部程序中,线程A和线程B对Holder的更新状态是随时可见的

Java安全发布的理解的更多相关文章

  1. Java语言的个人理解

    Java语言的个人理解(比价深层次吧) 大四的生活确实十分的奢靡,不锻炼,不读书,几乎就是当一天和尚撞一天钟的生活,太颓废了,还好自己不是这个样子,不过身体确实差了很多,昨天跑了一圈内环(4KM),今 ...

  2. Java常量字符串String理解

    Java常量字符串String理解 以前关于String的理解仅限于三点:1.String 是final类,不可继承2.String 类比较字符串相等时时不能用“ == ”,只能用  "eq ...

  3. java的final变量理解

    java的final变量理解 final基本类型是数值不能改变 final对象是引用不能改变,对象其自身是可以被修改的.

  4. 谈谈我对Java中CallBack的理解

    谈谈我对Java中CallBack的理解 http://www.cnblogs.com/codingmyworld/archive/2011/07/22/2113514.html CallBack是回 ...

  5. Gradle 1.12用户指南翻译——第46章. Java 库发布插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  6. java项目发布到linux服务器,tomcat正常启动但没加载项目

    问题描述: java项目发布到linux服务器,一切操作正确,linux命令启动tomcat后,查看日志启动tomcat正常,上传的war包已经解压成功,但是tomcat没加载项目. 解决方法: 1. ...

  7. 【Java】「深入理解Java虚拟机」学习笔记(1) - Java语言发展趋势

    0.前言 从这篇随笔开始记录Java虚拟机的内容,以前只是对Java的应用,聚焦的是业务,了解的只是语言层面,现在想深入学习一下. 对JVM的学习肯定不是看一遍书就能掌握的,在今后的学习和实践中如果有 ...

  8. Java提高篇之理解java的三大特性——继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  9. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

随机推荐

  1. MYSQL的binary解决mysql数据大小写敏感问题 《转载》

    BINARY不是函数,是类型转换运算符,它用来强制它后面的字符串为一个二进制字符串,可以理解为在字符串比较的时候区分大小写如下:mysql> select binary 'ABCD'='abcd ...

  2. Fire Net HDU 1045

    简单深搜,可以完全暴力,不会超时的. #include<iostream> #include<cstring> #include<cmath> using name ...

  3. 网络流(最大独立点集):POJ 1466 Girls and Boys

    Girls and Boys Time Limit: 5000ms Memory Limit: 10000KB This problem will be judged on PKU. Original ...

  4. Linux下p2p的聊天功能实现

    Linux下p2p的聊天功能实现细节 Do one thing at a time, and do well. 今天闲着没事,写一个P2P的点对点的聊天功能的小程序,我觉得对网络编程初学者的学习很有用 ...

  5. Codeforces Round #326 (Div. 1) - C. Duff in the Army 树上倍增算法

    题意:一个n个点的数, m个人住在其中的某些点上, 每个人的标号1-m, 询问u-v 路径上标号前a个人,并输出标号,a < 10. 作法, 利用倍增, ID[j][i] 表示i到i的第2^j个 ...

  6. 病毒侵袭持续中 - HDU 3065(AC自动机,判断子串个数)

    分析:依然是一个模板题,不过在写建立失败指针的地方竟然写错了三次....看来现在状态不太好.   代码如下: ============================================= ...

  7. OC类方法和实例方法 及常用的for/in方法

    类方法前面有+,实例方法前面有- 类方法和实例方法的区别在于,类方法不能使用实例变量. 使用类方法主要原因有: 1.类方法的使用不依赖于实例化一个对象,也就是说如果一个功能的实现不需要实例化对象,就可 ...

  8. hdu 4640 Island and study-sister(状态压缩dp)

    先处理前两个学长到达各个点所需要的最少时间,在计算前两个学长和最后一个学长救出所有学妹的最少时间. #include<stdio.h> #include<string.h> # ...

  9. mvc与mvvm

    mvc:被动型式的,也就是说,只有view有要求的时候,控制器才有反应 View     Controller       Model 可以把一个页面看作是由多个view组成 Controller控制 ...

  10. STL源码剖析—stl_config

    操作系统:centos 6.4STL源码版本:3.3 前言:    要看一个项目的源码,首先要选中切入点.    那么在sgi stl 标准库中,其切入点是什么呢?    答案是:stl_config ...