`
jeff312
  • 浏览: 76191 次
  • 性别: Icon_minigender_1
  • 来自: 新加坡
社区版块
存档分类
最新评论

JVM原理学习笔记(一)

    博客分类:
  • J2EE
阅读更多
    最近在阅读 《Inside the JVM》 这本书,结合一些日常工作学习中的感想,随便写一些东西,蜻蜓点水,不必有章法。

关于“单例同步”:
    一直有人在问单例对象的并发调用是否需要同步,基本属于“月经帖”了,答案是现成的满天下都是,但真正能让人心里踏实下来的解释寥寥无几。实际上,只要学习了一些JVM的运行原理,解释这个问题就不难了。
    如果一个类是单例的,比如某些DAO的设计,那么所有的线程来访问这个类的实例的时候,它们获得的都将是同一个对象,这是不言自明的。如果这些线程的当前操作是“互斥”的,那么每个线程就必须在取得该实例的访问资格的时候为该对象上锁,以独享该对象直到当前操作结束,以免在操作中途被其它线程介入而产生不可预知的结果。问题是,什么样的操作是“互斥”的呢?
    简单地说,互斥操作就是两个操作企图对它俩共享的某个资源进行修改,而修改的结果是不可预知的。于是问题就变成了,什么才是“共享的资源”?从纯粹java语法的角度这个问题没法解释,因为它遵循的是当前java虚拟机的规范描述。现假设两个线程正企图同时访问一个单例对象的方法,如,
int method1(int i) {
    int j = 3; 
    return i+j;
}

    一个规范的虚拟机线程在调用method1()的时候是这样做的:
    1) 把method1()的局部变量,包括参数,压入当前线程的栈;
    2) 从当前线程栈弹出变量j,并赋予数值3;
    3) 从当前线程栈弹出参数i,与j执行加法运算;
    4) 从当前线程栈中释放当前方法占用的栈帧,并把method1()的结果压入当前线程栈。
需要说明的是,当前线程栈是当前线程独有的,绝对不会被其它线程访问到。这样,只要你在method1()里面使用的全都是局部变量或参数,那就不需要为多线程的并发调用发愁,因为每个线程都有自己的栈帧,各不相干。

    复杂一点,如果method1()是这样定义的:
int method1(int i, SingletonClass singleObj) {
    singleObj.intValue ++;
    int j = i + singleObj.intValue;
    return j;
}

这下我们就不得不考虑线程同步问题了,这个方法显然包含了一个互斥的操作“singleObj.intValue ++;”。 前面说过,方法的参数会被压入当前线程私有的栈直到方法结束,但这里要注意的是,singleObj只是一个引用地址而非真正的对象实例,因此,尽管singleObj这个引用值是被压入线程私有栈去的,但真正的对象实例却是在堆里存放的,栈虽然是线程私有的,堆却是所有线程共享的,因此singleObj的成员变量intValue是完全有可能在当前线程执行第二行代码前被其它线程修改了的。比如说,线程1调用mothod1()的时候singleObj.intValue的值是1, i的值是2,那么正确的情况下,method1()的返回值应该是4。但当线程1和线程2几乎同时调用method1(),线程2恰好在线程1把intValue变成2之后的一瞬间又执行了一次singleObj.intValue ++,由于singleObj是单例,两个线程遇到的singleObj是同一个对象,因此这次运算将把intValue变成3。接下来线程1继续第二行代码,结果j的结果变成了i+3 = 2+3 = 5 。 如此一来,线程1调用method1()的返回结果究竟会是 4 还是 5 是无法确定的,只能凭运气,寄望线程2在线程1从调用method1()到取得返回值之间的这段时间打盹。在绝大多数情况下,这种“凭运气”的做法是不能接受的,我们需要向线程1保证,在它调用method1()期间绝不会收到线程2的干扰。做法如下:
int method1(int i, SingletonClass singleObj) {
    int j = 0;
    synchronize(singleObj) {
        singleObj.intValue ++;
        j = i + singleObj.intValue;
    }
    return j;
}

这个写法仍然有缺陷,因为线程2很可能在线程1执行int j = 0 的时候修改singleObj的intValue,所以比较可靠的应该在调用method1()之前锁住singleObj:
synchronize(singleObj) {
    int result = obj.method1(2, singleObj);
}


小小总结一下,“一个方法如果涉及对某个共享对象(或堆对象)的写操作,那么它必须同步该对象”这个说法在大多数情况下都对,但还有些失之笼统,或许这样说比较准确些,“如果一个方法对某共享对象的写操作会造成其它线程返回值的不确定性,则该方法应该同步该对象。”

更正:本文出现的书名应该是《Inside the JVM》,之前误写作《Deep Into JVM》了,感谢fantasybei网友提出来。本书是Java世界的经典著作,有兴趣的网友可以用书名在网上找到一大堆资料,其中文译名是《深入Java虚拟机》
分享到:
评论
18 楼 keating 2010-10-15  
faylai 写道
去我空间看吧!

http://faylai.iteye.com/blog/417490   
17 楼 miaow 2009-11-24  
引用是局部的,对象不是。
16 楼 qiuboboy 2009-11-23  
cn-done 写道
xiaohui5850 写道
int method1(int i, SingletonClass singleObj) {  
    int j = 0;  
    synchronized(singleObj) {  
        singleObj.intValue ++;  
        j = i + singleObj.intValue;  
    }  
    return j;  
}  

这个写法仍然有缺陷,因为线程2很可能在线程1执行int j = 0 的时候修改singleObj的intValue,所以比较可靠的应该在调用method1()之前锁住singleObj:

这是啥缺陷?没看出来
j是局部变量,这么锁肯定线程安全


在使用引用前进行锁定这是最好的解决方案!


不会吧,局部变量还这样玩啊
15 楼 jeff312 2009-10-23  
cn-done 写道

……
如果是这样,那不接受高等教育,随便进个培训班就可以做代码开发了。
很难有进一步的突破。
……


难道现在的市场不是这样吗?报一个培训班就可以写程序了。
14 楼 jeff312 2009-10-23  
ThinkInMyLife 写道
请问lz有 Inside the JVM 英文电子版吗?


貌似有的,但已经在我的1T硬盘里散佚了,哈

找英文版,去电驴上搜吧。
13 楼 cn-done 2009-10-22  
xiaohui5850 写道
int method1(int i, SingletonClass singleObj) {  
    int j = 0;  
    synchronized(singleObj) {  
        singleObj.intValue ++;  
        j = i + singleObj.intValue;  
    }  
    return j;  
}  

这个写法仍然有缺陷,因为线程2很可能在线程1执行int j = 0 的时候修改singleObj的intValue,所以比较可靠的应该在调用method1()之前锁住singleObj:

这是啥缺陷?没看出来
j是局部变量,这么锁肯定线程安全


在使用引用前进行锁定这是最好的解决方案!
12 楼 cn-done 2009-10-22  
我看的是《深入java虚拟机第二版》。基础中的基础。
很多同学可能会爆疑问:JVM看了有啥实际意义,貌似跟日常的开发扯不上太大的关系。
其实这种观念很是要不得。平常的开发,可能我们只属于技术的使用者,或者更多的时候是工具的使用者。
往往在别人多问几个为什么的时候就卡壳了。
如果是这样,那不接受高等教育,随便进个培训班就可以做代码开发了。
很难有进一步的突破。
回归纯真年代,从基础做起。
11 楼 浪客剑心 2009-10-22  
学习啦!!!楼主继续啊!
10 楼 ThinkInMyLife 2009-10-21  
请问lz有 Inside the JVM 英文电子版吗?
9 楼 ximenpiaohua 2009-10-20  
和JVM有关系吗?
更感觉是JMM
8 楼 patrickyao1988 2009-10-19  
java_my_life 写道
《深入Java虚拟机》这本书现在已经绝版啦!!
现在正在看电子版,痛苦啊!

淘宝还是有卖的。。。前阵子还买了本~~
7 楼 jeff312 2009-10-19  
说实话,虽然不是什么人都需要把虚拟机吃透,但作为一个合格的java程序员,至少要大致了解一下虚拟机的运行机制。
6 楼 faylai 2009-10-19  
去我空间看吧!
5 楼 java_my_life 2009-10-19  
《深入Java虚拟机》这本书现在已经绝版啦!!
现在正在看电子版,痛苦啊!
4 楼 taupo 2009-10-19  
有网络版吗???我穷啊
一直对JVM懵懵懂懂
3 楼 whaosoft 2009-10-19  
这本书没看过
2 楼 fantasybei 2009-10-19  
Deep into JVM?是inside jvm吧?
1 楼 Pigwen 2009-10-19  
谢谢,请问有没有《Deep into JVM》这本书介绍的网址

相关推荐

Global site tag (gtag.js) - Google Analytics