Java线程:是否所有共享变量都是挥发性的?(Java Threads: Should all shared variables be Volatile ? [duplicate])

编程入门 行业动态 更新时间:2024-10-27 07:26:49
Java线程:是否所有共享变量都是挥发性的?(Java Threads: Should all shared variables be Volatile ? [duplicate])

这个问题在这里已经有了答案:

Java volatile修饰符和synchronized块 3个答案

我想了解多线程如何在Java中工作。 我了解Volatile和Synchronization之间的区别。

Volatile是关于可见性,并不能保证同步。 当我们使用多线程环境时,每个线程都会在它们正在处理的变量的本地缓存上创建自己的副本。 更新此值时,更新首先发生在本地缓存副本中,而不是在实际变量中。 因此,其他线程对其他线程正在改变的值是不可知的。 这就是volatile进入画面的地方。 易失性字段会立即写入主内存,并从主内存中读取。

Thinking In Java片段 -

同步还会导致刷新到主内存,所以如果一个字段被同步方法或块完全保护,则不必使其变为易失性。

如果类只有一个可变字段,通常只使用volatile来代替同步是安全的。 同样,你的第一选择应该是使用synchronized关键字 - 这是最安全的方法,并且试图做其他任何事情都是有风险的。

但我的问题是,如果在同步块中,正在修改非易失性共享变量,其他线程是否会看到更新的数据? (因为所讨论的变量是非易失性的,所以其他线程应该从缓存而不是主内存中读取陈旧的数据)

如果对上述问题的回答是NO ,那么我可以得出结论:每次我使用同步时,我应该确保共享变量必须标记为volatile ?

如果答案是YES ,那么这是否意味着我总是可以使用synchronization而不是标记共享变量是volatile ?

ps:在问这个问题之前,我已经阅读了很多关于StackOverflow和其他网站的答案,但是我找不到我的问题的答案。

This question already has an answer here:

Java volatile modifier and synchronized blocks 3 answers

I am trying to understand how multithreading works in Java. I understand the difference between Volatile and Synchronization.

Volatile is about visibility and doesn't guarantee synchronization. When we are working with multithreading environments, each thread creates its own copy on a local cache of the variable they are dealing with. When this value is being updated, the update happens first in the local cache copy, and not in the real variable. Therefore, other threads are agnostic about the values that other threads are changing. And this is where volatile comes into picture. Volatile fields are immediately written through to main memory, and reads occur from main memory.

Snippet from Thinking In Java -

Synchronization also causes flushing to main memory, so if a field is completely guarded by synchronized methods or blocks, it is not necessary to make it volatile.

It’s typically only safe to use volatile instead of synchronized if the class has only one mutable field. Again, your first choice should be to use the synchronized keyword—that’s the safest approach, and trying to do anything else is risky.

But my question is, if in a synchronized block, a non volatile shared variable is being modified, will the other threads see the updated data ? (Since the variable in question is non volatile, other threads should read stale data from cache instead of main main memory)

If the answer to the above question is NO, then can I conclude that everytime I use synchronization, I should ensure that shared variables must be marked volatile ?

And if the answer is YES, then does that mean that I can always use synchronization instead of marking shared variables are volatile ?

p.s: Before asking this question, I have read through lot of answers on StackOverflow and on other sites, but I couldn't find the answer to my question.

最满意答案

为了简化一点:

volatile只提供了可见性:当你读取一个volatile变量时,你会得到两个保证:(1)即使它是在另一个线程中执行的,你也会看到最新的写入变量,(2)在volatile写入之前的所有写操作也是可见的。 synchronized给你的可见性和原子性 - 线程观察synchronized块中使用同一个监视器在synchronized块中执行的操作将会看到所有这些操作,或者看不到它们。

所以要回答你的问题,不,如果一个变量被写入synchronized块中,你不需要将它标记为volatile ,只要你总是使用同一个监视器从synchronized块中读取该变量即可。


这里有一些volatile的例子:

static class TestVolatile { private int i = 0; private volatile int v = 0; void write() { i = 5; v = 7; } void read() { //assuming write was called beforehand print(i); //could be 0 or 5 print(v); //must be 7 print(i); //must be 5 } void increment() { i = i + 1; //if two threads call the method concurrently //i could be incremented by 1 only, not 2: no atomicity } }

以及几个synchronized例子:

static class TestSynchronized { private int i = 0; private int j = 0; void write() { synchronized(this) { i = 5; j = 7; } } void read_OK() { synchronized(this) { //assuming write was called beforehand print(i); //must be 5 print(j); //must be 7 print(i); //must be 5 } } void read_NOT_OK() { synchronized(new Object()) { //not the same monitor //assuming write was called beforehand print(i); //can be 0 or 5 print(j); //can be 0 or 7 } } void increment() { synchronized(this) { i = i + 1; //atomicity guarantees that if two threads call the method //concurrently, i will be incremented twice } } }

To simplify a little:

volatile only provides visibility: when you read a volatile variable you get two guarantees: (1) you see the latest write to the variable, even if it was performed in another thread and (2) all the writes before that volatile write are also visible. synchronized gives you visibility AND atomicity - thread observing the actions performed in a synchronized block from a synchronized block using the same monitor will either see all of them or none of them.

So to answer your question, no, if a variable is written to within a synchronized block, you don't need to mark it volatile, provided that you always read that variable from a synchronized block using the same monitor.


Here are a few examples with volatile:

static class TestVolatile { private int i = 0; private volatile int v = 0; void write() { i = 5; v = 7; } void read() { //assuming write was called beforehand print(i); //could be 0 or 5 print(v); //must be 7 print(i); //must be 5 } void increment() { i = i + 1; //if two threads call the method concurrently //i could be incremented by 1 only, not 2: no atomicity } }

And a few examples with synchronized:

static class TestSynchronized { private int i = 0; private int j = 0; void write() { synchronized(this) { i = 5; j = 7; } } void read_OK() { synchronized(this) { //assuming write was called beforehand print(i); //must be 5 print(j); //must be 7 print(i); //must be 5 } } void read_NOT_OK() { synchronized(new Object()) { //not the same monitor //assuming write was called beforehand print(i); //can be 0 or 5 print(j); //can be 0 or 7 } } void increment() { synchronized(this) { i = i + 1; //atomicity guarantees that if two threads call the method //concurrently, i will be incremented twice } } }

更多推荐

本文发布于:2023-04-27 20:55:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1328613.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:都是   挥发性   线程   变量   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!