Is marking String type reference as Volatile safe?
Asked Answered
M

2

8

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?

Multitudinous answered 6/5, 2020 at 6:21 Comment(3)
Your title is vague. Rewrite to summarize your specific technical issue.Reverie
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.Inshore
Sorry about that. This title is set by a moderator, not me.Multitudinous
S
6

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.

Surah answered 6/5, 2020 at 6:29 Comment(5)
Yes, you would have to add synchronisation to +=, easiest done using an AtomicReference, in which case you don’t need volatileOliva
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.Multitudinous
@Multitudinous 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() method that applies the update in a threadsafe manner.Oliva
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.Inshore
@Inshore 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.Surah
U
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.

Unchaste answered 6/5, 2020 at 6:23 Comment(18)
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.Phthisic
As per your assumption in your answer, volatile is useless for primitives as well and only useful for the non thread safe data types.Phthisic
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.Unchaste
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. ?Phthisic
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 referencePhthisic
You just need to equals check before you use the ref right? Using volatile doesn't mean you don't need to check equalsUnchaste
what about the primitive like private int a= 10, do you think this will never need volatile ? int is thread safe and immutable.Phthisic
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, manUnchaste
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.Phthisic
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 ?Phthisic
Yes need to synchronize, not volatile, it's useless.Unchaste
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.Unchaste
@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.Phthisic
the question is not about volatile vs synchronised.Phthisic
yes, so I gave my option, no need to add volatile on StringUnchaste
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.Phthisic
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 @Phthisic says. (Rewrote comment due to Stack Overflow losing it.)Inshore
@Inshore 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.Phthisic

© 2022 - 2024 — McMap. All rights reserved.