是否需要将java servlet中的多个线程访问的变量声明为volatile?

时间:2009-07-29 14:51:15

标签: java servlets concurrency multithreading

在书Java Servlet Programming中,第54页有一个示例servlet,它在后台线程中搜索素数。每次客户端访问servlet时,都会返回最近找到的素数。

用于存储最近找到的素数的变量声明为:

long lastprime = 0;

由于这个变量是从多个线程(正在进行计算的后台线程和正在访问它的任何客户端线程)开始访问的,所以它不需要声明为volatile还是以某种方式使其访问同步?

5 个答案:

答案 0 :(得分:8)

是的,假设您确实希望在任何线程上看到最近计算的素数,它应该是易失性的,或者通过synchronized块/方法以线程安全的方式访问。另外,正如注释中所指出的,非易失性长变量可能无法原子更新 - 因此您可以看到旧值的前32位和新值的后32位(反之亦然)。

我之前忘记了原子性方面,因为当你确保获得最近发布的值时,它几乎总是自动解决,并确保你完全发布新值。实际上,这几乎总是你想要的,所以如果你的代码工作正常,那么原子性就不会成为问题。

它不是SingleThreadModel servlet吗?这显然会产生影响。

另一种选择是使用AtomicLong

答案 1 :(得分:1)

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

答案 2 :(得分:1)

线程之间有一个干净的读/写分割;一个主题“发布”其他人阅读的最后一个主要内容,然后你就可以让它变得不稳定。

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

答案 3 :(得分:1)

假设Java 5或更高版本然后将其声明为volatile,则会定义明确定义的语义为here。根据从代码维护者心中消除疑问的原则,我会使用volatile,说“是的,我知道多个线程使用这个变量”。

有趣的问题是没有宣布它不稳定的影响。如果你有一个素数,那么它是否是最新的? Volatile确保从内存中获取taht值,而不是任何“CPU”缓存,因此您应该获得更新的值。

看到部分分配的可能性怎么样?你真的不走运,看到一个长的LSB是旧值的一部分而MSB是不同价值的一部分吗?好吧,对多头和双打的分配不是原子的,所以理论上是的!

Ergo,volatile或synchronized不仅仅是一个很好的......你需要它

答案 4 :(得分:0)

Java中volatile变量的语义不足以使增量操作(lastprime ++)原子化,除非你能保证变量只是从一个线程写入 - 而不是在servlet的情况下

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

相关问题