rawData
rawData

Reputation: 799

is String thread safe?

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

Answers (4)

Stephen C
Stephen C

Reputation: 718788

I think this can summarized as follows:

  1. Operations on String objects are thread-safe. (They are thread safe because String objects are immutable, but the why is not directly relevant to your example.)
  2. Unsynchronized read and write operations1 on non-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

markspace
markspace

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

simo-r
simo-r

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 Strings 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

Dylan
Dylan

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.

  • String 1 - "Hello", Address: 0x449345
  • String 2 - "There", Address: 0x058345
  • String 3 - "World", Address: 0x004934

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

Related Questions