简体   繁体   English

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

[英]Does a variable accessed by multiple threads in a java servlet need to be declared volatile?

In the book Java Servlet Programming , there's an example servlet on page 54 which searches for primes in a background thread. Java Servlet Programming一书中,第54页有一个示例Servlet,它在后台线程中搜索素数。 Each time a client accesses the servlet, the most recently found prime number is returned. 每次客户端访问servlet时,都会返回最近找到的素数。

The variable which is used to store the most recently found prime is declared as such: 用于存储最近找到的素数的变量声明为:

long lastprime = 0;

Since this variable is begin accessed from multiple threads (the background thread that's doing the calculations and any client threads that are accessing it), doesn't it need to be declared volatile or have its access synchronized in some way? 由于此变量是从多个线程(正在执行计算的后台线程以及正在访问该线程的任何客户端线程)开始访问的,因此是否不需要将其声明为volatile或以某种方式对其访问进行同步?

Yes, assuming you really want to see the most recently calculated prime on any thread, it should either be volatile or be accessed in a thread-safe way via synchronized blocks/methods. 是的,假设您确实想查看任何线程上最新计算的素数,则它应该是易失性的,或者可以通过synchronized块/方法以线程安全的方式进行访问。 Additionally, as pointed out in the comments, non-volatile long variables may not be updated atomically - so you could see the top 32 bits of an old value and the bottom 32 bits of a new value (or vice versa). 此外,正如注释中指出的那样,非易失性长变量可能不会自动更新-因此您可以看到旧值的前32位和新值的后32位(反之亦然)。

I forgot about the atomicity side of things earlier because it's almost always solved automatically by when you make sure you get the most recently published value, and make sure you fully publish new values. 我忘记了事物的原子性方面,因为当您确定获得最新发布的值并确保完全发布新值时,它几乎总是自动解决。 In practice this is almost always what you want, so atomicity becomes a non-issue if your code is working properly to start with. 实际上,这几乎总是您想要的,因此,如果您的代码开始正常工作,那么原子性就不会成为问题。

It's not a SingleThreadModel servlet is it? 这不是SingleThreadModel servlet吗? That would obviously make a difference. 那显然会有所作为。

Another alternative would have been to use AtomicLong . 另一个选择是使用AtomicLong

Yes. 是。 A servlet's variables aren't thread-safe. Servlet的变量不是线程安全的。

There is a clean read/write split between the threads; 线程之间进行了清晰的读写拆分; one thread "publishes" the last prime for others to read, then you can get away with making it volatile. 一个线程“发布”最后一个质数以供其他人阅读,那么您就可以使其不稳定。

If the access pattern involved some read-modify-write sequences or the like, then you'd have to synchronize the access to the field. 如果访问模式涉及一些读-修改-写序列等,那么您将必须同步对该字段的访问。

Assuming Java 5 or later then declaring it volatile gives well-defined semantics as desscribed here . 假定Java 5或更高版本,然后声明为volatile,则可得到定义良好的语义,如此处所述 On the principle of removing doubt from the code maintainer's mind I would use volatile, saying "yes I know that multiple threads use this variable". 基于从代码维护者的思想中消除疑问的原则,我将使用volatile,说“是的,我知道多个线程使用此变量”。

The intersting question is the effect of not declaring it volatile. 有趣的问题是没有声明它是易变的。 Provided that you got a prime, does it matter if it's the very latest available? 只要有黄金,这很重要,如果它的最新可用? Volatile ensures taht values are taken from memory, not any "CPU" caches, so you should get a more up to date value. 易失性可确保taht值是从内存中获取的,而不是从任何“ CPU”缓存中获取的,因此您应该获取最新的值。

What about the possibility of seeing a partial assigment? 看到部分身分的可能性怎么样? Could you get really unlucky and see a long whose LSBs are part of an old value and MSBs part of a different value? 您是否真的会倒霉,看到很长的LSB是旧值的一部分,而MSB是不同值的一部分? Well, assignments to longs and doubles are not atomic, so in theory yes! 好吧,多头和双打的分配不是原子的,所以理论上是!

Ergo, volatile or synchronized is not just a nice-to-have ... you need it 因此,易失性或同步不仅是一个不错的选择……您需要它

Semantics of volatile variable in Java are not strong enough to make the increment operation (lastprime++) atomic, unless you can guarantee that the variable is written only from a single thread - not in servlet's case Java中的volatile变量的语义不够强大,不足以使增量操作(lastprime ++)成为原子操作,除非您可以保证该变量仅从单个线程写入-而在servlet的情况下则不能

On the other hand, using AtomicXXX variables is thread-safe, as long as no compounded operations are performed. 另一方面,只要不执行任何复合操作,使用AtomicXXX变量都是线程安全的。 There will be window of vulnerability when updating more than one atomic variables, even though each call to is atomic. 更新多个原子变量时将存在漏洞窗口,即使每次调用都是原子的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM