2009-07-29 47 views
1

Java Servlet Programming这本书中,第54页的示例servlet在后台线程中搜索素数。每次客户端访问servlet时,都会返回最近找到的素数。java servlet中多个线程访问的变量是否需要声明为volatile?

它用于存储最近发现黄金被宣布为变量:

long lastprime = 0; 

因为这个变量开始从多个线程(后台线程正在做的计算和任何客户端线程访问的正在访问它),是否需要声明为volatile或以某种方式同步其访问?

回答

8

是的,假设您真的想在任何线程上看到最近计算的素数,它应该是易失性的或者通过​​blocks/methods以线程安全的方式访问。此外,正如注释中指出的那样,非易失性长变量可能不会自动更新 - 因此您可以看到旧值的前32位和新值的下32位(反之亦然)。

我忘记了事物的原子性侧早些时候,因为它几乎总是通过当你确保你得到最新发布的价值,并确保您完全发布新值自动解决。在实践中,这几乎总是你想要的,所以如果你的代码能够正常工作,原子性就成为一个非问题。

这不是SingleThreadModel servlet是它吗?这显然会有所作为。

另一种选择是使用AtomicLong

+1

我会为AtomicLong投票 – 2009-07-29 14:56:51

1

是的。一个servlet的变量不是线程安全的。

1

线程之间存在干净的读/写拆分;一个线程“发布”最后一个素数供其他人阅读,那么你就可以使其变得不稳定。

如果访问模式涉及一些读取 - 修改 - 写入序列等,那么您必须将访问权限同步到该字段。

1

假设Java 5或更高版本,则声明它为volatile将提供明确定义的语义,如描述here。关于从代码维护者的头脑中消除疑问的原则,我会使用volatile,并说“是的,我知道多个线程使用这个变量”。

问题是没有声明它是挥发性的影响。假设你有a素数,如果它是最新的可用性,它是否重要?易失性确保从内存中获取值,而不是任何“CPU”缓存,所以您应该获得更新的值。

如何看到部分分配的可能性?您是否真的不走运,看到一个长期的LSB是旧价值的一部分,MSB是不同价值的一部分?那么,长期和双打的任务不是原子的,理论上是这样!

Ergo,易失性或同步不只是一个很好的... ...你需要它在Java中的volatile变量的

0

语义是没有强大到足以使增值业务(lastprime ++)原子,除非你能保证变量从单个线程只写了 - 不是在servlet的情况下

另一方面,只要没有执行复合操作,使用AtomicXXX变量是线程安全的。更新多个原子变量时会出现漏洞窗口,即使每次调用都是原子的。

相关问题