Java multithread synchronized keyword details of six

  • 2020-04-01 04:34:45
  • OfStack

Lock, the synchronized keyword, on behalf of this method is equivalent to no matter which one thread (thread A, for example), run to this method, to check if any other thread B or C, D, etc.) are using this method (or other synchronization method of that class), so to are using synchronized methods such as thread B (or C, D) after running this method to run this thread A, if not, lock the caller, and then run directly. It includes two USES: synchronized methods and synchronized blocks.

Multithreaded synchronization locks resources so that only one thread can operate at the same time, and synchronization solves problems that can occur when multiple threads access the same time.

The synchronization mechanism can be implemented using the synchronized keyword.

When the synchronized keyword modifies a method, the method is called a synchronized method.

When a synchronized method finishes executing or an exception occurs, the lock is automatically released.

The use of the synchronized keyword is resolved with an example.

1. Differences in whether or not the synchronized keyword is used

Example program 1


public class ThreadTest
  {
    public static void main(String[] args)
    {
      Example example = new Example();
      Thread t1 = new Thread1(example);
      Thread t2 = new Thread1(example);
      t1.start();
      t2.start();
    }
  }
  class Example
  {
    public synchronized void execute()
    {
      for (int i = 0; i < 10; ++i)
      {
        try
        {
          Thread.sleep(500);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        System.out.println("Hello: " + i);
      }
    }
  }
  class Thread1 extends Thread
  {
    private Example example;
    public Thread1(Example example)
    {
      this.example = example;
    }
    @Override
    public void run()
    {
      example.execute();
    }
  }

The result of the execution of this example program will vary greatly whether the execute() method is preceded by the synchronized keyword.

If the synchronized keyword is not added, then both threads execute the execute() method at the same time, and the output is two groups concurrently.

If you add the synchronized keyword, you print a set of 0 through 9, and then the next set, indicating that the two threads are executing in sequence.

2. Multithreading of multiple methods

To change the program, add another method execute2() to the Example class.

Then you write a Thread2 class, and the run() method in Thread2 executes execute2(). Both methods in the Example class are modified by the synchronized keyword.

Example program 2


 public class ThreadTest
{
  public static void main(String[] args)
  {
    Example example = new Example();
    Thread t1 = new Thread1(example);
    Thread t2 = new Thread2(example);
    t1.start();
    t2.start();
  }
}
class Example
{
  public synchronized void execute()
  {
    for (int i = 0; i < 20; ++i)
    {
      try
      {
        Thread.sleep((long) Math.random() * 1000);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
      System.out.println("Hello: " + i);
    }
  }
  public synchronized void execute2()
  {
    for (int i = 0; i < 20; ++i)
    {
      try
      {
        Thread.sleep((long) Math.random() * 1000);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
      System.out.println("World: " + i);
    }
  }
}
class Thread1 extends Thread
{
  private Example example;
  public Thread1(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    example.execute();
  }
}
class Thread2 extends Thread
{
  private Example example;
  public Thread2(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    example.execute2();
  }
}

  If the synchronized keyword is removed, the two methods execute concurrently and do not affect each other.

But as the example shows, even two methods:

The result of execution is always the execution of the output of one thread followed by the execution of another thread.

Description:

If an object has multiple synchronized methods, and at some point a thread has entered a synchronized method, no other thread can access any of the object's synchronized methods until the method completes execution.

Conclusion:

When the synchronized keyword modifies a method, the method is called a synchronized method.

Each object in Java has a lock (lock), or a monitor (monitor), when a thread object access a synchronized method, the object is locked, no other threads are unable to visit the object of a synchronized method (here refers to all of the synchronized methods, not just the same way), until the thread after the execution method (or throw exceptions), to release the object's lock, other threads can be synchronized method to access the object.

Note that the object is locked, and if it is a different object, there is no restrictive relationship between the objects.

When you pass in a new Example object when you try to construct a second thread object in your code, there are no constraints between the execution of the two threads.

3. Consider a static synchronization approach

When a method modified by the synchronized keyword is also static, as mentioned earlier, a non-static synchronized method locks an object, but a static method does not belong to an object, it belongs to a Class, and it locks the Class object of the Class in which the method resides.

No matter how many objects a Class generates, they correspond to the same Class object.

Example program 3


 public class ThreadTest
{
  public static void main(String[] args)
  {
    Example example = new Example();
    Thread t1 = new Thread1(example);
    //Here, static method synchronization does not allow multiple threads to execute simultaneously, even if different objects are passed in
    example = new Example();
    Thread t2 = new Thread2(example);
    t1.start();
    t2.start();
  }
}
class Example
{
  public synchronized static void execute()
  {
    for (int i = 0; i < 20; ++i)
    {
      try
      {
        Thread.sleep((long) Math.random() * 1000);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
      System.out.println("Hello: " + i);
    }
  }
  public synchronized static void execute2()
  {
    for (int i = 0; i < 20; ++i)
    {
      try
      {
        Thread.sleep((long) Math.random() * 1000);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
      System.out.println("World: " + i);
    }
  }
}
class Thread1 extends Thread
{
  private Example example;
  public Thread1(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    Example.execute();
  }
}
class Thread2 extends Thread
{
  private Example example;
  public Thread2(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    Example.execute2();
  }
}

So if it's a static method case (execute() and execute2() with the static keyword), even if you pass two different Example objects to two threads, they're still mutually exclusive and must execute one before the next.

Conclusion:

If a synchronized method is static, when a thread accesses the method, it locks not the object that the synchronized method is in, but the Class object that the synchronized method is in. In Java, no matter how many objects a Class has, those objects correspond to a unique Class object, so when a thread accesses two static, synchronized methods of two objects of the same Class, they execute in sequence, meaning that one thread executes the method first, and the other thread does not start until it finishes.

4. The synchronized block

Synchronized block:


  synchronized(object)
  {    
  }

Means that the thread locks the object when it executes. Note that this object can be an object of any class, or you can use the this keyword.

This allows you to specify which objects to lock.

Example program 4


 public class ThreadTest
{
  public static void main(String[] args)
  {
    Example example = new Example();
    Thread t1 = new Thread1(example);
    Thread t2 = new Thread2(example);
    t1.start();
    t2.start();
  }
}
class Example
{
  private Object object = new Object();
  public void execute()
  {
    synchronized (object)
    {
      for (int i = 0; i < 20; ++i)
      {
        try
        {
          Thread.sleep((long) Math.random() * 1000);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        System.out.println("Hello: " + i);
      }
    }
  }
  public void execute2()
  {
    synchronized (object)
    {
      for (int i = 0; i < 20; ++i)
      {
        try
        {
          Thread.sleep((long) Math.random() * 1000);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        System.out.println("World: " + i);
      }
    }
  }
}
class Thread1 extends Thread
{
  private Example example;
  public Thread1(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    example.execute();
  }
}
class Thread2 extends Thread
{
  private Example example;
  public Thread2(Example example)
  {
    this.example = example;
  }
  @Override
  public void run()
  {
    example.execute2();
  }
} 

Example program 4 achieves the same effect as example program 2, which is to make two threads execute in order, instead of concurrently. When one thread executes, the object object is locked, and the other thread cannot execute the corresponding block.

A synchronized method is effectively equivalent to enclosing all the statements in a method with a synchronized block, then passing the this keyword in parentheses of the synchronized block. Of course, if it is a static method, it is the class object that needs to be locked.

Only a few lines of code of a method might involve thread synchronization problem, so the synchronized blocks more fine-grained than synchronized methods to control the access of multiple threads, only the contents of the synchronized block cannot be accessed by multiple threads at the same time, other statements in the method still can access by multiple threads at the same time (including the synchronized block before and after).

Note: data protected by synchronized should be private.

Conclusion:

A synchronized method is a coarse-grained concurrency control that can be executed by only one thread at a time.

A synchronized block, on the other hand, is a fine-grained concurrency control that only synchronizes the code in the block.


Related articles: