俗话说得好,工欲善其事必先利其器,对于Java开发者来说,简单了解Java虚拟机某些特性有益于提升开发者的内功。为什么我们在编写Java代码前,需要安装并且配置好JDK?JDK内置的这些包功能为什么这么强大?为什么我们的程序会出现内存泄露呢?为什么在代码中加入Synchronized关键字多线程访问程序不会出现数据不一致问题?好多类似的问题,在我们了解JVM之后就会得到答案。
《深入理解Java虚拟机》 周志明著 这本书大家普遍推荐。
主要组成部分:
public class happenBeforeDemo { private int value = 0; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public static void main(String[] args) { happenBeforeDemo happenBeforeDemo = new happenBeforeDemo(); new Thread(() -> happenBeforeDemo.setValue(22)).start(); new Thread(() -> System.out.println(happenBeforeDemo.getValue())).start(); } }
大家猜测下输出的结果是什么?0还是1?而这段代码遵循的是什么原则?
先行并发原则是什么?
程序次序规则 管程锁定规则 volatile变量规则 线程启动规则 线程终止规则 线程中断规则 对象终结规则 传递性
衡量线程安全性问题 不要受时间顺序的干扰 而是一切以先行发生原则为基准
由于第一个线程和第二个线程分别调用setValue()和getValue()两个函数,不在同一个线程中,程序次序规则不适用,由于没有同步块则自然不会发生lock操作与unlock操作,管程锁定不适合。由于value没有添加volatile修饰,自然就没有volatile变量规则,后面的线程启动,线程终止,线程中断,对象终结规则也和这里没有关系。最后一条传递性也不适用。所以该操作为线程不安全操作。
解决方案也比较常见
/** *线程A 访问getValue 线程B访问setValue *解决方案 synchronized volatile */
我们知道这段代码最终会编译成.class文件,在我们查看字节码之前,先了解下以下简单的知识。
字节码的格式说明:
1:魔术与Class文件的版本 2:常量池 3:访问标志 4:类索引父索引与接口索引集合 5:字段表集合 6:方法表集合 7:属性表集合(1code 2Exceptions 3 LineNumberTable 4LocalVariableTable 5 SourceFile属性 6ConstantValue属性 7 InnerClasses 8 Deprecated以及Synthetic属性 9 StackMapTable属性(JDK1.6后加的) 10 Signature属性(JDK1.5后加的)11 BootstrapMethods属性(JDK1.7后加的))。。。。
更多内容关注微信公众号