Details the synchronized keyword in Java

  • 2020-04-01 04:27:11
  • OfStack

The keyword in the Java language, when used to modify a method or block of code, ensures that at most one thread executes the code at a time.

When two concurrent threads access this synchronized(this) synchronized block of code in the same object object, only one thread can execute at a time. Another thread must wait for the current thread to finish executing the block before it can execute.

However, when a thread accesses a synchronized(this) synchronized block of an object, another thread can still access a non-synchronized (this) synchronized block of the object.

3. In particular, when a thread accesses a synchronized(this) synchronized block of an object, access by other threads to all other synchronized(this) synchronized blocks of the object is blocked.

The third example also applies to other synchronized code blocks. That is, when a thread accesses a synchronized(this) synchronized block of code of an object, it acquires the object lock of that object. As a result, access by other threads to all synchronized code parts of the object object is temporarily blocked.

  The above rules are also applicable to other object locks.

For example:    
When two concurrent threads access this synchronized(this) synchronized block of code in the same object object, only one thread can execute at a time. Another thread must wait for the current thread to finish executing the block before it can execute.


package ths;

public class Thread1 implements Runnable { 
   public void run() { 
     synchronized(this) { 
        for (int i = 0; i < 5; i++) { 
          System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); 
        } 
     } 
   } 
   public static void main(String[] args) { 
     Thread1 t1 = new Thread1(); 
     Thread ta = new Thread(t1, "A"); 
     Thread tb = new Thread(t1, "B"); 
     ta.start(); 
     tb.start(); 
   } 
}

Results:    
        A synchronized loop 0  
        A synchronized loop 1  
        A synchronized loop 2  
        A synchronized loop 3  
        A synchronized loop 4  
        B synchronized loop 0  
        B synchronized loop 1  
        B synchronized loop 2  
        B synchronized loop 3  
        4 B synchronized loop

However, when a thread accesses a synchronized(this) synchronized block of an object, another thread can still access a non-synchronized (this) synchronized block of the object.


package ths;

public class Thread2 { 
   public void m4t1() { 
     synchronized(this) { 
        int i = 5; 
        while( i-- > 0) { 
          System.out.println(Thread.currentThread().getName() + " : " + i); 
          try { 
             Thread.sleep(500); 
          } catch (InterruptedException ie) { 
          } 
        } 
     } 
   } 
   public void m4t2() { 
     int i = 5; 
     while( i-- > 0) { 
        System.out.println(Thread.currentThread().getName() + " : " + i); 
        try { 
          Thread.sleep(500); 
        } catch (InterruptedException ie) { 
        } 
     } 
   } 
   public static void main(String[] args) { 
     final Thread2 myt2 = new Thread2(); 
     Thread t1 = new Thread( new Runnable() { public void run() { myt2.m4t1(); } }, "t1" ); 
     Thread t2 = new Thread( new Runnable() { public void run() { myt2.m4t2();  } }, "t2" ); 
     t1.start(); 
     t2.start(); 
   } 
}

Results:    
        T1:4  
        T2:4  
        T1:3  
        T2:3  
        T1:2  
        T2:2  
        T1:1  
        T2:1  
        T1:0  
        T2:0

3. In particular, when a thread accesses a synchronized(this) synchronized block of an object, access by other threads to all other synchronized(this) synchronized blocks of the object is blocked.

Modify the thread2.m4t2 () method:          


 public void m4t2() { 
     synchronized(this) { 
        int i = 5; 
        while( i-- > 0) { 
          System.out.println(Thread.currentThread().getName() + " : " + i); 
          try { 
             Thread.sleep(500); 
          } catch (InterruptedException ie) { 
          } 
        } 
     }

   }

Results:

        T1:4  
        T1:3  
        T1:2  
        T1:1  
        T1:0  
        T2:4  
        T2:3  
        T2:2  
        T2:1  
        T2:0

The third example also applies to other synchronized code blocks. That is, when a thread accesses a synchronized(this) synchronized block of code of an object, it acquires the object lock of that object. As a result, access by other threads to all synchronized code parts of the object object is temporarily blocked.

Thread2.m4t2() is modified as follows:      


public synchronized void m4t2() { 
     int i = 5; 
     while( i-- > 0) { 
        System.out.println(Thread.currentThread().getName() + " : " + i); 
        try { 
          Thread.sleep(500); 
        } catch (InterruptedException ie) { 
        } 
     } 
   }

Results:    
        T1:4  
        T1:3  
        T1:2  
        T1:1  
        T1:0  
        T2:4  
        T2:3  
        T2:2  
        T2:1  
        T2:0

V. the above rules are also applicable to other object locks:


package ths;

public class Thread3 { 
   class Inner { 
     private void m4t1() { 
        int i = 5; 
        while(i-- > 0) { 
          System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i); 
          try { 
             Thread.sleep(500); 
          } catch(InterruptedException ie) { 
          } 
        } 
     } 
     private void m4t2() { 
        int i = 5; 
        while(i-- > 0) { 
          System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); 
          try { 
             Thread.sleep(500); 
          } catch(InterruptedException ie) { 
          } 
        } 
     } 
   } 
   private void m4t1(Inner inner) { 
     synchronized(inner) { //Using object locks
     inner.m4t1(); 
   } 
   private void m4t2(Inner inner) { 
     inner.m4t2(); 
   } 
   public static void main(String[] args) { 
     final Thread3 myt3 = new Thread3(); 
     final Inner inner = myt3.new Inner(); 
     Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1"); 
   Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2"); 
   t1.start(); 
   t2.start(); 
 } 
}

Results:

Although thread t1 acquires an object lock on Inner, thread t2 accesses the asynchronous part of the same Inner. So the two threads don't interfere with each other.

        T1: Inner m4t1 () = 4  
        T2: Inner m4t2 () = 4  
        T1: Inner m4t1 () = 3  
        T2: Inner m4t2 () = 3  
        T1: Inner m4t1 () = 2  
        T2: Inner m4t2 () = 2  
        T1: Inner m4t1 () = 1  
        T2: Inner m4t2 () = 1  
        T1: Inner m4t1 () = 0  
        T2: Inner m4t2 () = 0

Now add synchronized to Inner. M4t2 () :


 private synchronized void m4t2() { 
     int i = 5; 
     while(i-- > 0) { 
        System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); 
        try { 
          Thread.sleep(500); 
        } catch(InterruptedException ie) { 
        } 
     } 
   }

Results:

Although thread t1 and t2 access two unrelated parts of the same Inner object, t2's access to inner-.m4t2 () is also blocked because t1 acquired the object lock to Inner first, because m4t2() is a synchronization method in Inner.

        T1: Inner m4t1 () = 4  
        T1: Inner m4t1 () = 3  
        T1: Inner m4t1 () = 2  
        T1: Inner m4t1 () = 1  
        T1: Inner m4t1 () = 0  
        T2: Inner m4t2 () = 4  
        T2: Inner m4t2 () = 3  
        T2: Inner m4t2 () = 2  
        T2: Inner m4t2 () = 1  
        T2: Inner m4t2 () = 0
The synchronized keyword, which includes two USES: Synchronized methods and Synchronized blocks .  
1. Synchronized methods: Declare a synchronized method by adding the synchronized keyword to the method declaration. Such as:  
Public synchronized void accessVal(int newVal);  
Synchronized method to control access to a class member variables: each class instance corresponds to a lock, each a synchronized method must be called the method of class instance lock is able to perform, otherwise affiliated thread block, once method execution, is dominant in the lock, lock release until returned from this method, has been blocked thread in order to get the lock, back into the executable. This mechanism ensures that the same time for each class instance, all its declared as a member of the synchronized function as much as there is only one in the executable state (because only one can get at most the class instance corresponding lock), thus effectively avoid the class member variable access conflict (as long as all may visit a class member variable method is declared synchronized).  
In Java, not only class instances, each class also has a lock, so we can also declare the class's static member function as synchronized to control its access to the class's static member variables.  
Disadvantages of synchronized methods: Declaring a large method as synchronized can have a significant effect on efficiency. Typically, declaring the method run() of a thread class as synchronized will cause it to never succeed in calling any of the synchronized methods of this class because it is running for the entire life of the thread. Of course we can solve this problem by putting code that accesses class member variables into specialized methods, declaring them synchronized, and calling them from the main method, but Java provides a better solution: synchronized blocks.  
2. The synchronized block: A synchronized block is declared by the synchronized keyword. The grammar is:  
Synchronized (syncObject) { 
// code that allows access control  
}  
A synchronized block is a block of code in which the code must obtain a lock on the object syncObject (which, as mentioned earlier, can be an instance or class) in order to execute, as described earlier. Because you can target any code block, and you can specify any locked object, you have more flexibility.  

The above is a detailed example of the Java synchronized keyword, which I hope will help you learn how to use it better.


Related articles: