javaarraylistthread-safetysynchronizedsynchronized-block

Why is the Synchronized Block invalidated?


As known that List is not thread-safe, I add synchronized to the code in 2 methods shown below.

1.

public class TestSyn 
{ 
  public static void main( String[] args ) throws InterruptedException 
  {
    List<String> list = new ArrayList<>();
    for( int i = 0; i < 100000; i++ ) 
    {
      new Thread( 
        ()->
        {
          synchronized( list )
          {
            list.add( Thread.currentThread().getName() );
          }
        } ).start();
    }
    Thread.sleep( 2000 );
    System.out.println( list.size() );
  }
}
public class TestSyn2 
{
  public static void main( String[] args ) throws InterruptedException 
  {
    List<String> list = new ArrayList<>();
    synchronized( list )
    {
      for( int i = 0; i < 10000; i++ ) 
      {
        new Thread( () -> list.add( Thread.currentThread().getName() ) )
          .start();
      }
    }
    Thread.sleep( 2000 );
    System.out.println( list.size() );
  }
}

The result of the first method was always 10000 which was correct,while the second one sometimes is less than 10000.

So, why does the second one cannot output the right result?


Solution

  • Just expanding on the answer that already was provided in comments (above).


    The difference between your two versions is in which thread or threads lock the list object's intrinsic mutex.

    In the first version, the synchronized(list) statement is executed by each one of the 100,000 new threads that your program creates. It is lexically contained within the lambda expression that generates the Runnable delegates for each of the new threads.

    In the second version, the synchronized(list) statement is only ever executed one time, by the program's main thread. It appears outside of the lambda. The 100,000 new threads mutate the shared list without any synchronization, and the fact that main() executes inside the synchronized block means nothing because no other thread ever tries to synchronize on the same object.


    Also note: Although the first version of your program is "safe," it also is kind of pointless. None of your 100,000 new threads ever does anything at all outside of the synchronized block. That means, none of your 100,000 new threads ever does anything concurrently with any of the others. But concurrency is the only reason for creating threads.