Java: volatile enough to make classes threadsafe?

允我心安 提交于 2019-12-05 02:24:17

问题


I have a question about the volatile statement in Java. Please look at this constructed example:

class Master {
    // Foo is a class with thread-safe methods
    public volatile Foo foo;
}

class Worker1 implements Runnable {
    protected Master master

    void run() { ... };
}

class Worker2 implements Runnable {
    protected Master master

    void run() { ... };
}

We have 2 worker threads which hold a reference to an object of class Master running at the same time. During their work, both have to access methods of master.foo. At some point, the Foo object of master will be changed by one of the worker threads. Now my question: Does the use of volatile make the whole construction thread-safe? I am asking this because in a Java tutorial from Oracle it says

However, there are actions you can specify that are atomic:

  • Reads and writes are atomic for reference variables [...]

Atomic actions cannot be interleaved, so they can be used without fear of thread interference.

I just would like to make sure that I understood this correctly.

Thanks in advance :)


回答1:


Reads and writes of references are always atomic in Java, so there is no danger of, for example, seeing the reference in some half-updated state. If this is what you mean by "thread safe" then the operation is thread safe with or without the keyword.

But volatile is not about atomicity, it affects whether threads can cache writes locally. volatile would force writes to be written back to main memory and be visible to other threads. If that is what you mean by thread-safe, then yes you need this keyword.

volatile itself does not affect whether method calls on foo exclude other threads or not. If that's what you mean you want to use synchronized, and in a different place.




回答2:


volatile ensures that a thread reading the variable will see the new value set in this variable before by another thread. It won't see a stale value stored in a processor cache.

Whether it makes the whole program thread-safe depends on what the program does, how it uses the variable, and how the Foo class is designed.




回答3:


volatile is not enough.

I believe this example demonstrates one situation where volatile is not enough:

Shared object:

public class Blammo
{
  public String kapow;
}

Code in thread 1:

Blammo blammo = new Blammo();
blammo.kapow = "zowie";
if ((blammo.kapow != null) && (blammo.kapow.isEmpty()))
{
  ...
}

Code in thread 2:

blammo.kapow = null;

Thread 1 is executing and executes (blammo.kapow != null).
Thread 1 swaps out and Thread 2 swaps in.
Thread 2 executes (blammo.kapow = null).
Thread 2 swaps out and Thread 1 swaps in.
Thread 1 now executes (blammo.kapow.isEmpty()) and throws a null pointer exception.




回答4:


If the only thing you do is setting this variable, than yes, volatile is enough. As pointed out in the comments, you need volatile to make the changes visible (however, you will not have any corrupt updates without volatile, like you could have with long or double, see below).

By default, reading and writing of reference variables (references to objects) are atomic, as are reading and writing to most primitive types (except for long and double).

With volatile you can make sure that reads and writes to variables of type long and double are also atomic, which you don't need in this case.

So, yes, in this example, it is enough. However, if you're planning on sending more complex messages, consider using tools from java.util.concurrent.*



来源:https://stackoverflow.com/questions/8538429/java-volatile-enough-to-make-classes-threadsafe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!