Reputation: 799
A string is immutable which means that once you amend the value its create a new reference and leave the previous reference value as it was.
However, I don't understand when someone arguing :
Strings are thread safe as they are immutable
Consider below code:
private String str = "1";
ExecutorService executorService = Executors.newFixedThreadPool(10);
IntStream.range(0, 1000).forEach((i)-> executorService.submit(()-> {
str = str +"1";
}));
executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println(str.length());
If it was thread safe then it should print 1001
while it is always print less than expected value.
I understand the above code will create 1001
immutable references which each one is thread-safe on its own, but as a developer, still can not using something immutable and expect the end-result
would be thread safe.
IMHO, immutability is not guaranteed thread safety.
Could someone please explain to me how a String is threaded safe?
Update:
Thanks for your answers, I understand that each string could be thread safe, but my point was, there is no direct relationship between thread safety and immutability when you use them in other methods.
for example, an immutable object can be used in the stateful object and ended with the non-thread safe result and also a mutable object could be used in a synchronised method and ended up with a thread-safe result.
Upvotes: 3
Views: 14171
Reputation: 718788
I think this can summarized as follows:
String
objects are thread-safe. (They are thread safe because String
objects are immutable, but the why is not directly relevant to your example.)final
shared2 variables are not thread-safe, irrespective of the type of the variable.Your example does str = str + 1;
. That combines operations on String
objects with operations on an unsynchronized shared variable (str
). It is not thread-safe because of the latter.
1 - More precisely, operations where there is no happens before relationship between writes and reads to guarantee required memory visibility properties, and there is no locking to guarantee required atomicity properties. ("Required" means required for correctness of the algorithm ...)
2 - Shared means visible to and used by more than one thread. If a variable is only visible to or used by one thread, it is said to be thread-confined and it is effectively not shared.
Upvotes: 5
Reputation: 11020
Your str
reference is not immutable, you mutate it every time you reassign its value. Since you're sharing mutable state between threads with no synchronization or mutex, the result is not safe.
The following worked for me the 5 times I tried it. Note I added mutex around concatenating your string.
public class QuickyTest {
private static String str = "1";
public static void main( String[] args ) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool( 10 );
IntStream.range( 0, 1000 ).forEach( ( i ) -> executorService.submit( () -> {
append( "1" );
}
) );
executorService.awaitTermination( 10, TimeUnit.SECONDS );
System.out.println( str.length() );
executorService.shutdown();
}
private static synchronized void append( String s ) {
str = str + s;
}
}
Always prints "1001".
Upvotes: 0
Reputation: 733
It's not printing 1001
because it depends on when each thread take the current memory reference of str
(because the reference is mutable so not thread-safe).
Look at this example, we have 3 threads {T1,T2,T3}.
T1 gets str reference and change it so we have str = "11"; T2 and T3 get
str
reference (simultaneously) and change it so, now you have, T2 ->str= "111"
and T3 ->str = "111"
;
When str
is updated it could be updated with str value from T2 or T3 ( depends on execution) but essencially you cannot think that each thread execute sequencially the operation.
So String
s are immutable so thread-safe because each thread just modify their own reference but you have to sychronize the update logic if you need it.
If you want to print 1001
from your code you need to sychronize the access to str (monitors,locks,semaphores, sychronized keyword, etc).
Btw, String
are thread-safe because if you try to change it (in any way) you will create another memory reference so two (or more) thread cannot manipulate the same String
reference or better they have the same string reference but when they manipulate it the new string is stored in a new reference).
Upvotes: 0
Reputation: 1395
Its important to know how memory works in programming languages. The variable str is not a String Object, like you would think. But it is instead a reference to a String Object, with some address.
Modifying what str points to, does not modify the string that it points to. In fact what happens is something like this:
We have a pool of memory, in our pool is three strings. Each string has an address that allows us to find it.
We have a variable that is pointing to each one, we will call them a,b, and c.
If we said: System.out.println(a);
Java would print Hello
. But a is not "Hello". Instead a is something that contains 0x449345. The computer then goes: "Okay, i'll go take what is at 0x449345 and print it out." When it goes and looks at that address, it finds the string "Hello".
However, if you said: a = "NEW STRING";
a would not point to any of our previous addresses. Instead a new address is created and "NEW STRING" is placed inside that memory location.
This is also how Garbage Collection works in Java. Once you set a equal to "NEW STRING" it no longer points to 0x449345, this tells the garbage collector that that object is safe to remove. This is how your program cleans up after itself, and does not eat up tons of RAM.
Because of this, the reference that points to a string, is not thread safe but the actual object IS! Any immutable object is thead safe, because you CANNOT modify that object at all, you can only modify what your variable points to. You would have to point to a different object entirely to "modify", your immutable object.
Upvotes: 7