7

I've read some posts and articles saying that we shouldn't declare java objects as volatile, because as a result, only the reference becomes volatile. Here are some examples:

link-1 link-2 link-3

What Sonar suggests is 'Non-primitive fields should not be "volatile"', however, it also suggests that the problem described refers to mutable objects 'Similarly, marking a mutable object field volatile means the object reference is volatile but the object itself is not'.

My question is: is it safe to declare java String as volatile?

nits.kk
  • 5,204
  • 4
  • 33
  • 55
jaros
  • 323
  • 1
  • 3
  • 15
  • 2
    Your title is vague. Rewrite to summarize your specific technical issue. – Basil Bourque May 06 '20 at 06:24
  • Not really clear what you mean by 'safe'. The volatile keyword does exactly what it's specified to do for all types of fields, whether they point to objects or not. It will not explode, for example. And because String instances are immutable, they cannot themselves malfunction due to use by multiple threads, regardless of what you do with them or whether you use volatile fields to do it. But that doesn't mean that what volatile does is *sufficient* to make an application behave as you want. Adding volatile everywhere will not magically make applications thread-safe. – Boann May 07 '20 at 02:24
  • Sorry about that. This title is set by a moderator, not me. – jaros May 07 '20 at 06:35

2 Answers2

5

Because String objects are immutable, only the reference is modified by operators like = and +=. Therefore, volatile is safe for String, as it applies to the reference itself. This applies to other immutable objects as well, just as it does to primitives.

Clarification:

+= itself is not thread-safe even on a volatile String, as it is not atomic and consists of a read followed by a write. If something affects the String object between the read and write, it may lead to unexpected results. While the resulting String will still be valid, it may have an unexpected value. In particular, some changes may "overwrite" other changes. For instance, if you have a String with the value "Stack " and one thread tries to append "Overflow" while the other tries to append "Exchange", there is a possibility that only one change will be applied. This applies to primitives as well. If you are interested, more details about this particular issue (mostly in the context of primitives) can be found here.

Evan Bailey
  • 168
  • 1
  • 12
  • 3
    Yes, you would have to add synchronisation to `+=`, easiest done using an `AtomicReference`, in which case you don’t need `volatile` – Bohemian May 06 '20 at 07:01
  • 1
    So `volatile` is safe for `String` but not when the `+=` operator is used? I actually like the idea of `AtomicReference` as suggested by @Bohemian. Sounds less confusing than `volatile` itself. – jaros May 06 '20 at 07:56
  • 1
    @jaros normal string concatenation is a non-threadsafe operation, due to another thread modifying the value/reference after reading it but before writing the new value. `AtomicReference` provides the [getAndUpdate()](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html#getAndUpdate-java.util.function.UnaryOperator-) method that applies the update in a threadsafe manner. – Bohemian May 06 '20 at 18:34
  • 1
    Your "clarification" confuses things. `+=` **is** thread-safe, if by "thread-safe", we mean that String objects themselves will not internally malfunction. Nothing can "affect" them, because they are immutable. The `+=` operation is not *atomic*, so if multiple threads use `+=` at the same time, you may overwrite some appended text, but you will always still see *some* *functioning* String object afterwards. – Boann May 07 '20 at 02:33
  • @Boann I meant that `+=` is not thread-safe in the sense that race conditions can lead to unexpected results. While the String object is still functional, it may have a totally different value than would be expected if multiple threads are involved. I will edit my answer to be more clear about this. – Evan Bailey May 07 '20 at 02:52
0

Java String is final Class, immutable and thread-safe.
There is no middle state for String, will not confuse in the multi-thread cases with lock or synchronize. There is no need to do that.

PatrickChen
  • 1,350
  • 1
  • 11
  • 19
  • 2
    what do you mean by that ? Yes String is thread safe in context to its internal state which is immutable. What about the reference. If you have an instance variable `private String ref = "some-string";` Now there is all probability that a thread may modify the reference `ref = "some-other-string"`. Moreover answer must have details and should add value more than the comment. A single liners can very well be part of the comments. – nits.kk May 06 '20 at 06:38
  • 1
    As per your assumption in your answer, `volatile` is useless for primitives as well and only useful for the non thread safe data types. – nits.kk May 06 '20 at 06:45
  • 1
    What's `volatile` use for? Always used in the multi-thread situation, you want other threads to view the changes immediately. But for `String`, you don't need that, there is no middle state for String, any thread change it, it'll immediately detect by other threads. – PatrickChen May 06 '20 at 06:45
  • 2
    What about `private String ref = "some-string";` a method `public void set(String s){ ref = s;}` now Thread T1 invokes `set("Abc")` and Thread T2 invokes `set("123")` and Thread T3 reads the string in a while loop, what do you think, may be the behaviour. ? – nits.kk May 06 '20 at 06:49
  • 2
    moreover read my first comment. Its not about the protection against internal state but rather than the referenced variable. Until unless the reference is marked as static final , you do not have the reference of type String as thread safe. The String Object is thread safe not its non static final reference – nits.kk May 06 '20 at 06:51
  • You just need to `equals` check before you use the `ref` right? Using `volatile` doesn't mean you don't need to check `equals` – PatrickChen May 06 '20 at 06:51
  • 1
    what about the primitive like `private int a= 10`, do you think this will never need volatile ? `int` is thread safe and immutable. – nits.kk May 06 '20 at 06:53
  • Yes, private int a = 10, never need `volatile`. If you're using `a` in multi-thread. You just need to check `a`'s value, before you use it. The thing you need is Lock or Synchronize, not volatile, man – PatrickChen May 06 '20 at 06:55
  • 2
    volatile guarantees that any read will be from the memory and not from the thread cache. When you read any reference then its value can be changes or not decides the usage of volatile. – nits.kk May 06 '20 at 06:56
  • 2
    what do you mean by check `a` value ? You are sure without any synchronised contruct, and withou it being declared as volatile , the value of a when you **check a's value** is read from memory and not thread local cache ? – nits.kk May 06 '20 at 07:01
  • Yes need to synchronize, not `volatile`, it's useless. – PatrickChen May 06 '20 at 07:03
  • If you create `int a` inside the thread, it's already hread-safe, will use thread stack. Only when you create `static int a` then it's multi-thread usable because it's `static` it will allocate in the heap not thread-local, `volatile` still useless. – PatrickChen May 06 '20 at 07:06
  • 1
    @PatricckChen `volatile` is never useful if read and writes happen within synchronised blocks on same monitor. The question is in regards is it safe to declare String as volatile. String being immutable is fine to declare as volatile. The reference to any mutable objects when marked as volatile is not safe as its internal state can change. – nits.kk May 06 '20 at 07:19
  • the question is not about volatile vs synchronised. – nits.kk May 06 '20 at 07:23
  • yes, so I gave my option, no need to add `volatile` on String – PatrickChen May 06 '20 at 07:33
  • Suppose , We have Main thread : private s = "abc"; Now thread T1 writes s = "xyz", thread T2 writes s = "pqr" , thread T3 writes s="def";` and Thread T4 reads s and stores the string with timestamps in a while loop. Here if s is marked as volatile, it is guaranteed that thread T4 will get the contents from the memory and not from the thread cache. As per tour comment it looks you are confused between Thread stack & Thread cache, both r different thread stack holds the local states when a method is invoked where as Thread cache caches the frequently accessed values for performance. – nits.kk May 06 '20 at 11:14
  • 1
    I interpreted your answer as "String objects are always immutable and internally thread-safe, and so they will not malfunction due to use by multiple threads, whether you use volatile or not", which is correct, and so I upvоted it. But the comments indicate you don't know what volatile does. There certainly are valid cases where a private instance String or int field can need to be volatile as @nits.kk says. (Rewrote comment due to Stack Overflow losing it.) – Boann May 07 '20 at 02:48
  • @Boann Yes i agree and The advantages or limitations of volatile is a separate topic for discussion, here the context is simply if making a string field as volatile will guarantee to have the read value from the memory, (value consists of both the object as a whole and its internal state) to which answer is yes as against an field referring to any mutable object where volatile is not enough to safeguard against inconsistent reads. – nits.kk May 07 '20 at 03:02