The purpose of life is to grow, the essence of life is to change, the challenge of life is to conquer


The purpose of life is to grow, the essence of life is to change, the challenge of life is to conquer


Today, let’s talk about the use of synchronized and how it is used

As we all know, there are three major features in the Java memory model: atomicity, visibility, and orderliness

Synchronized: ensures visibility and atomicity

In the Java memory model, synchronized specifies that when a thread locks, it first emptying the working memory –> copying the latest variable into the main memory –> executing the code –> flushing the value of the changed shared variable into the main memory –> releasing the mutex

Orderliness: The natural orderliness of Java programs can be summed up in a sentence: if you observe in one thread, all operations are naturally ordered, and if you observe in one thread, all operations are out of order

Synchronized enables variables or code blocks to be accessed by only one thread at a certain time, thus reducing the consumption of memory. What is locked is the instance of the object, which is stored in the heap instead of the code block. If other threads want to use this object, they must wait for the object to be released before they can obtain it. Therefore, the idea of synchronized can also be understood as pessimistic lock

See the following uses the double check lock singleton mode

     private volatile static Singleton singleton;

     public static Singleton getSingleton() {if(null == singleton){        
           synchronized (Singleton.class) {            
              if(null == singleton){ singleton = new Singleton(); }}}return singleton;
     }

     public static void main(String[] args) {    
       for(int i = 0; i<10; i++){ new Thread(newRunnable() {            
          @Override            
          public void run() {                
              System.out.println(Thread.currentThread().getName()+":"+Singleton.getSingleton().hashCode());            
          }}).start();    
     }Copy the code



As you can see, the Singleton object is volatile and nulled twice. Volatile is used to make the variable change visible (volatile is also a keyword). The second nulling is because the first nulling is Singleton and only one instance needs to be created. The previously created instance is returned directly, so you do not need to execute the code in the synchronous method most of the time, greatly improving performance. The second sentence is empty after executing thread 1 check for the first time that the CPU thread 2 has been executive power, the next thread 2 lock, create an instance Thread 1 at this moment, get the executive power, also create an instance, the results will lead to create multiple instances, so need a second check inside the synchronized code, if the instance is empty, is to create, This ensures that only one object is created

Synchronized can be added to methods as well as code blocks

class Sync{
     public synchronized void test() {          
         System.out.println("The test start..");          
         
         try {              
             Thread.sleep(1000);          
         } catch (InterruptedException e) {             
             e.printStackTrace();          
         }          
             System.out.println("The test end..");      
      }  
}    

class MyThread extends Thread {        

     public void run() {          
        Sync sync = new Sync();          
        sync.test();      
     }  
}   
 
public class Main {        
    
      public static void main(String[] args) {          
          for(int i = 0; i < 3; i++) { Thread thread = new MyThread(); thread.start(); }}}}Copy the code

Running results:

The test start.. The test start.. The test start.. The end of the test.. The end of the test.. The end of the test..

Didn’t change, didn’t see synchronized in action

Let’s try adding synchronized to the block to reduce the granularity of the lock

class Sync {        

      public void test(a) {          
         synchronized (Sync.class) {              
              System.out.println("The test start..");              
         
         try {                  
              Thread.sleep(1000);              
         } catch (InterruptedException e) {                 
              e.printStackTrace();              
         }              
         System.out.println("The test end.."); }}}class MyThread extends Thread {        
      public void run(a) {          
          Sync sync = newSync(); sync.test(); }}public class Main {        
     
        public static void main(String[] args) {         
        
           for (int i = 0; i < 3; i++) {              
               Thread thread = newMyThread(); thread.start(); }}}Copy the code

Running results:testStart..testThe end..testStart..testThe end..testStart..testThe end..Copy the code

Synchronized locks not this, but the Class object of the synchronized Class

Reentrancy of Synchronized

Syncronized is an atomic-based internal locking mechanism that is reentrant
A thread that calls the syncronized method simultaneously calls another synchronized method of the object inside its method body
When a subclass inherits from a parent class, a subclass can also call the parent’s synchronized methods via a reentrant lock

conclusion

Synchronized locks either instances of that class or objects that are passed in. Again, synchronized makes variables or blocks of code accessible only to one thread at a time