BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #27157同步于 2013/10/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

请教一个在多线程变量同步问题

sutar
2013/10/9镜像同步6 回复
没学过 java,现在要写一个 java 程序。类似于 socket 网络聊天室吧。 然后,大致代码如下。在 ExpServer 中存在俩 sub class(不知道java里是不是这么叫?nested class?)。 然后这俩 class 多线程运行(在 main 中实例化)。CoreThread 通过改变变量 isPrint 触发 PrintThread 动作( PrintThread 一直 while(true) )。 问题来了,在 CoreThread 的 run() 中改变 isPrint = true ,可是 PrintThread 里 if(isPrint) 一直为 false。可是,如果在 if(isPrint) 之前执行一句 System.out.println(isPrint) 那么 if(isPrint) 为 true了。。 好凌乱,这是什么情况? @nuanyangyang public class ExpServer extends ServerSocket{ private static boolean isPrint = false; class PrintThread extends Thread { public PrintThread() { start(); } @Override public void run() { while (true) { System.out.println("Print state: " + isPrint); if (isPrint) { System.out.println("Print"); } } } } class CoreThread extends Thread { public CoreThread() { start(); } @Override public void run() { isPrint = true; } } }
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
sutar机器人#1 · 2013/10/9
套在 synchronized(this){} 里就有用了。。这到底是什么共享机制
nuanyangyang机器人#2 · 2013/10/9
根本原因是CPU的不同核心之间的cache一致性。在多线程环境中,一个核心写的内存在另一个核心中不一定立即可见。如果每次都写回共享的内存(或者某些CPU的L3Cache也是共享的),性能会很差。 对于Java来说,语言有规定“Memory Model”,规定的就是这种行为。对于非volatile的变量而又没有同步的话,多线程的读写相互可见关系是不保证的。而在一些可以保证的happen before关系成立的情况下,可以保证先写后读时读可以看见写。 Java的Happens-before关系包括: 1. If x and y are actions of the same thread and x comes before y in program order, then hb(x, y). 2. An unlock on a monitor happens-before every subsequent lock on that monitor. 3. A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field. 第1条很显然。 第2条指的就是synchronize。解锁发生在加锁之前。所以如果第二个线程成功地加了锁,那么可以保证读写顺序。 第3条指的是对volatile域的读写本身属于同步的动作,Java要保证对这些域的读写在多个线程看来是一致的,比如,两个volatile域a=b=0。先写了a=1,又写了b=2。另一个线程如果看到b=2,那么一定要看到a=1。 但是,注意从来就没有说一个线程写了以后另一个线程“立即”就能看到。想象一下物理的CPU里一个核心怎么才能最快地让另一个核心知道某件事发生,而且操作系统什么时候才能将另一个线程调度到“执行”状态。“立即”这个词很危险,现实的物理世界中“同时”这个概念都不是总是成立的,可以看看相对论中常见的火车和闪电悖论。
sutar机器人#3 · 2013/10/9
想起来了,跟 CPU 的 cache 有关,比如 L1 Cache / L2 Cache miss rate 什么的。 Computer Architecture 里有讲对吧?只考虑语言层面的事情了,没考虑底层的实现问题了。谢大神。 ;P 【 在 nuanyangyang 的大作中提到: 】 : 根本原因是CPU的不同核心之间的cache一致性。在多线程环境中,一个核心写的内存在另一个核心中不一定立即可见。如果每次都写回共享的内存(或者某些CPU的L3Cache也是共享的),性能会很差。 : 对于Java来说,语言有规定“Memory Model”,规定的就是这种行为。对于非volatile的变量而又没有同步的话,多线程的读写相互可见关系是不保证的。而在一些可以保证的happen before关系成立的情况下,可以保证先写后读时读可以看见写。 : Java的Happens-before关系包括: : ...................
EvilKirin机器人#4 · 2013/10/10
我擦,这个板凳好有深度。。。 我简单补充下,JCIP里边最重要最容易忽略的一个概念就是data race和race condition。 在这里从表面上看就是data race在作怪嘛: The term race condition is often confused with the related term data race, which arises when synchronization is not used to coordinate all access to a shared non-volatile field. Code with data race has no useful defined semantics under the JMM. 额,原文摘抄,有些内容没有弄进来,楼主有时间自己看看咯。 另外线程间通信的有效性在编译器和处理器以及cache subsystem重排序的情况下是需要memory barrier来进一步强制sequential consistency的。 如果楼主有兴趣,咱可以推荐一点文章的。
SandFlee机器人#5 · 2013/10/10
【 在 EvilKirin 的大作中提到: 】 : 我擦,这个板凳好有深度。。。 : 我简单补充下,JCIP里边最重要最容易忽略的一个概念就是data race和race condition。 : 在这里从表面上看就是data race在作怪嘛: : ................... 推荐点吧,这段时间正好看并发的东西
EvilKirin机器人#6 · 2013/10/11
抱歉有点晚。。 http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html 这一篇是关于JMM的faq,绝对值得深入阅读,你看到作者名字就明白了 http://g.oswego.edu/dl/jmm/cookbook.html 这一篇是来自j.u.c包作者Doug Lea(如雷贯耳吧)的,有一定难度。不太确定是否是一个比较好的入门文章,但是肯定是必读的。 以上这两个会涉及到一些底层的内容,特别是第一篇。毕竟并发跟多核和cache以及memory都是密不可分的。如果你有心去探索,推荐另外一篇名为what every programmer should know about memory的超级长的文章,涉及相当多的硬件的知识,包你爽到爆。我记得有中文翻译过来的,貌似发在开源中国的译文版。 http://www.infoq.com/cn/articles/ftf-java-volatile 聊聊并发系列的第一篇,作者是方腾飞 http://ifeve.com/jvm-thread/ 并发编程网,貌似方腾飞是其中文章的主要作者之一 这些东西如果你都完全能够理解吸收,我想在找工作的时候任何关于多线程或并发的内容都难不倒你。当然,你在看这些文章的时候还会去发现更多有意思的东西,祝你好运。 【 在 SandFlee 的大作中提到: 】 : 推荐点吧,这段时间正好看并发的东西