返回信息流没学过 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;
}
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #27157同步于 2013/10/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
请教一个在多线程变量同步问题
sutar
2013/10/9镜像同步6 回复
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
根本原因是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里一个核心怎么才能最快地让另一个核心知道某件事发生,而且操作系统什么时候才能将另一个线程调度到“执行”状态。“立即”这个词很危险,现实的物理世界中“同时”这个概念都不是总是成立的,可以看看相对论中常见的火车和闪电悖论。
想起来了,跟 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关系包括:
: ...................
我擦,这个板凳好有深度。。。
我简单补充下,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的。
如果楼主有兴趣,咱可以推荐一点文章的。
【 在 EvilKirin 的大作中提到: 】
: 我擦,这个板凳好有深度。。。
: 我简单补充下,JCIP里边最重要最容易忽略的一个概念就是data race和race condition。
: 在这里从表面上看就是data race在作怪嘛:
: ...................
推荐点吧,这段时间正好看并发的东西
抱歉有点晚。。
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 的大作中提到: 】
: 推荐点吧,这段时间正好看并发的东西