年复一年,我试图了解部分与内存模型和并发交易的Java规范。我不得不承认我失败了。是的,我了解锁和“同步”,wait()和notify()。我可以很好地使用它们,谢谢。对于“ volatile”的作用,我什至不清楚。但是所有这些都不是来自语言规范,而是来自一般经验。
这是我要问的两个示例问题。我对特定答案不太感兴趣,因为我需要了解答案是如何从规范中得出的(或者可能是我得出结论,规范没有答案)。
一句话警告:如果这里 有 答案,请指望其中有很多是错误的。我不打算发布详细信息的原因之一是,因为我很确定至少在某些方面 会 犯错。我的意思是,当我说每个认为自己可以回答这个问题的人实际上有足够的严谨性来解决这个问题时,对社区没有任何不尊重。(Joe Duffy最近发现了一些让.NET内存模型感到惊讶的东西。如果他能弄错的话,像我们这样的凡人也可以。)
我将仅从一个方面提供一些见解,因为它常常被误解:
波动性和原子性之间是有区别的。人们通常认为原子写入是易失性的(即,如果写入是原子的,则无需担心内存模型)。这不是真的。
易变性是关于一个线程(在源代码中,从逻辑上来说)执行读取是否会“看到”另一线程所做的更改。
原子是关于是否有任何机会,如果一个变化 是 看到的,只有变化的部分可以看出。
例如,写入一个整数字段。保证是原子的,但不是易变的。这意味着如果有(从foo.x = 0开始):
Thread 1: foo.x = 257; Thread 2: int y = foo.x;
可能y是0或257。由于原子性约束,不会是其他任何值(例如256或1)。但是,即使您知道在“挂墙时间”中在线程1中的代码之后执行的线程2中的代码,也可能存在奇数缓存,内存访问了“移动”等。使变量为xvolatile将解决此问题。
y
x
我将剩下的工作交给真正的诚实至善专家。