Java Concurrency 02---Traditional Thread Mutual Exclusion Technology---synchronized

  When multiple threads operate the same resources at the same time, they will encounter concurrency problems, such as bank transfers, ticketing systems, etc. In order to avoid these problems, we can use the synchronized keyword to solve them. The following is a summary of the common usage of synchronized. First write a program with concurrency problems, as follows:

public class TraditionalThreadSynchronized {

    public static void main(String[] args) {
        //在静态方法中不能new内部类的实例对象
        //private Outputer outputer = new Outputer();
        new TraditionalThreadSynchronized().init();
    }

    private void init() {
        final Outputer outputer = new Outputer();
        //线程1打印:duoxiancheng
        new Thread(new Runnable() {         
            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    outputer.output1("duoxiancheng");
                }

            }
        }).start();;

        //线程2打印:eson15
        new Thread(new Runnable() {         
            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    outputer.output1("eson15");
                }

            }
        }).start();;
    }

    static class Outputer {
        //自定义一个字符串打印方法,一个个字符的打印
        public void output1(String name) {
            int len = name.length();
            for(int i = 0; i < len; i++) {
                System.out.print(name.charAt(i));
            }
            System.out.println("");     
        }       
    }
}
    
    

      A method of printing strings is defined in the inner class Outputer, which prints one character by one character, so that it is easier to intuitively see the concurrency problem, because the disorder of the character sequence indicates that there is a problem. Then start two threads in the init method, one thread prints "duoxiancheng", and the other thread prints "eson15". Take a look at the running results:

    eson15duoxianche
    ng
    eson15
    duoxiancheng
    duoxiancheng
    eson15
    esduoxiancheng
    on15
    duoxiancheng

      There has been a problem. In order to solve this problem, you can use the synchronized synchronization code block to synchronize the public part, but you need to give it a lock. This lock is an object, which can be any object, but the premise is that two It is easy to understand that each thread must use the same object lock. Then output1()add the synchronized block of code to the method below:

    static class Outputer {
        private String token = ""; //定义一个锁
        public void output1(String name) {
            synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
            //如果用name就不行了,因为不同的线程进来name是不一样的,不是同一个name
            {
                int len = name.length();
                for(int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println("");     
            }
        }
    }   
        
        

        After the above transformation, the thread safety problem is basically solved, but it can be further extended. If the synchronized keyword is added to the method, then what is this synchronization lock? output2()We write another method in the Outputer class :

      static class Outputer {
          private String token = ""; //定义一个锁
          public void output1(String name) {
              synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
              {
                  int len = name.length();
                  for(int i = 0; i < len; i++) {
                      System.out.print(name.charAt(i));
                  }
                  System.out.println("");     
              }
          }   
      
          public synchronized void output2(String name) {
      
              int len = name.length();
              for(int i = 0; i < len; i++) {
                  System.out.print(name.charAt(i));
              }
              System.out.println("");     
          }   
      }
          
          

          The internal implementation logic of the method is exactly the same, the only difference is that synchronized is added to the method, then we let one of the two threads in the init() method call the output1(String name)method and the other call output2(String name)the method. It can be seen from the results that the thread safety issue appeared again. The reason for the problem is not difficult to find: now both methods are synchronized, but there is still a problem when two threads are calling two different methods, that is to say, they are still playing each other... Then the problem lies in this Locked, indicating that the two do not use the same lock!
          If we change output1()the token in synchronized in the method to this, there will be no problem in running again. This means that when the synchronized keyword modifies a method, the synchronization lock is this, which is equivalent to a code blocksynchronized(this) {...} .
          Continuing to extend, now write a static method in the Outputer class output3(String name), and also let synchronized to modify this static method.

        static class Outputer {
            private String token = ""; //定义一个锁
            public void output1(String name) {
                synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
                {
                    int len = name.length();
                    for(int i = 0; i < len; i++) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println("");     
                }
            }   
        
            public static synchronized void output3(String name) {
        
                int len = name.length();
                for(int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println("");     
                }   
            }
        }
            
            

            Then in the init() method one thread calls the output1()method and the other thread calls the output3()method. Undoubtedly, there will definitely be thread safety issues again. But how to solve it? Because the static method is loaded when the class is loaded, the lock should be the bytecode object of the class. Then change the token to Outputer.classsolve the problem, which means that when the synchronized keyword modifies the static method, the synchronization lock is the bytecode object of the class, which is equivalent to the code blocksynchronized(classname.class) {...} .
            
            Finally, to sum up:

          • A lock for a synchronized block of code is an arbitrary object . As long as different threads are executing the same synchronized code block, this lock is set arbitrarily.
          • The lock of a synchronized function is fixed by this . When it is necessary to synchronize with the logic in the synchronization function, the lock in the code block must be this.
          • The lock for a statically synchronized function is the bytecode file object of the class to which the function belongs . The object can be obtained with this.getClass()methods or 当前类名.classrepresented .

            When multiple threads operate the same resources at the same time, they will encounter concurrency problems, such as bank transfers, ticketing systems, etc. In order to avoid these problems, we can use the synchronized keyword to solve them. The following is a summary of the common usage of synchronized. First write a program with concurrency problems, as follows:

          public class TraditionalThreadSynchronized {
          
              public static void main(String[] args) {
                  //在静态方法中不能new内部类的实例对象
                  //private Outputer outputer = new Outputer();
                  new TraditionalThreadSynchronized().init();
              }
          
              private void init() {
                  final Outputer outputer = new Outputer();
                  //线程1打印:duoxiancheng
                  new Thread(new Runnable() {         
                      @Override
                      public void run() {
                          while(true) {
                              try {
                                  Thread.sleep(5);
                              } catch (InterruptedException e) {
                                  // TODO Auto-generated catch block
                                  e.printStackTrace();
                              }
                              outputer.output1("duoxiancheng");
                          }
          
                      }
                  }).start();;
          
                  //线程2打印:eson15
                  new Thread(new Runnable() {         
                      @Override
                      public void run() {
                          while(true) {
                              try {
                                  Thread.sleep(5);
                              } catch (InterruptedException e) {
                                  // TODO Auto-generated catch block
                                  e.printStackTrace();
                              }
                              outputer.output1("eson15");
                          }
          
                      }
                  }).start();;
              }
          
              static class Outputer {
                  //自定义一个字符串打印方法,一个个字符的打印
                  public void output1(String name) {
                      int len = name.length();
                      for(int i = 0; i < len; i++) {
                          System.out.print(name.charAt(i));
                      }
                      System.out.println("");     
                  }       
              }
          }
            
            

              A method of printing strings is defined in the inner class Outputer, which prints one character by one character, so that it is easier to intuitively see the concurrency problem, because the disorder of the character sequence indicates that there is a problem. Then start two threads in the init method, one thread prints "duoxiancheng", and the other thread prints "eson15". Take a look at the running results:

            eson15duoxianche
            ng
            eson15
            duoxiancheng
            duoxiancheng
            eson15
            esduoxiancheng
            on15
            duoxiancheng

              There has been a problem. In order to solve this problem, you can use the synchronized synchronization code block to synchronize the public part, but you need to give it a lock. This lock is an object, which can be any object, but the premise is that two It is easy to understand that each thread must use the same object lock. Then output1()add the synchronized block of code to the method below:

            static class Outputer {
                private String token = ""; //定义一个锁
                public void output1(String name) {
                    synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
                    //如果用name就不行了,因为不同的线程进来name是不一样的,不是同一个name
                    {
                        int len = name.length();
                        for(int i = 0; i < len; i++) {
                            System.out.print(name.charAt(i));
                        }
                        System.out.println("");     
                    }
                }
            }   
              
              

                After the above transformation, the thread safety problem is basically solved, but it can be further extended. If the synchronized keyword is added to the method, then what is this synchronization lock? output2()We write another method in the Outputer class :

              static class Outputer {
                  private String token = ""; //定义一个锁
                  public void output1(String name) {
                      synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
                      {
                          int len = name.length();
                          for(int i = 0; i < len; i++) {
                              System.out.print(name.charAt(i));
                          }
                          System.out.println("");     
                      }
                  }   
              
                  public synchronized void output2(String name) {
              
                      int len = name.length();
                      for(int i = 0; i < len; i++) {
                          System.out.print(name.charAt(i));
                      }
                      System.out.println("");     
                  }   
              }
                
                

                  The internal implementation logic of the method is exactly the same, the only difference is that synchronized is added to the method, then we let one of the two threads in the init() method call the output1(String name)method and the other call output2(String name)the method. It can be seen from the results that the thread safety issue appeared again. The reason for the problem is not difficult to find: now both methods are synchronized, but there is still a problem when two threads are calling two different methods, that is to say, they are still playing each other... Then the problem lies in this Locked, indicating that the two do not use the same lock!
                  If we change output1()the token in synchronized in the method to this, there will be no problem in running again. This means that when the synchronized keyword modifies a method, the synchronization lock is this, which is equivalent to a code blocksynchronized(this) {...} .
                  Continuing to extend, now write a static method in the Outputer class output3(String name), and also let synchronized to modify this static method.

                static class Outputer {
                    private String token = ""; //定义一个锁
                    public void output1(String name) {
                        synchronized(token) //任何一个对象都可以作为参数,但是该对象对于两个线程来说是同一个才行
                        {
                            int len = name.length();
                            for(int i = 0; i < len; i++) {
                                System.out.print(name.charAt(i));
                            }
                            System.out.println("");     
                        }
                    }   
                
                    public static synchronized void output3(String name) {
                
                        int len = name.length();
                        for(int i = 0; i < len; i++) {
                            System.out.print(name.charAt(i));
                        }
                        System.out.println("");     
                        }   
                    }
                }
                  
                  

                    Then in the init() method one thread calls the output1()method and the other thread calls the output3()method. Undoubtedly, there will definitely be thread safety issues again. But how to solve it? Because the static method is loaded when the class is loaded, the lock should be the bytecode object of the class. Then change the token to Outputer.classsolve the problem, which means that when the synchronized keyword modifies the static method, the synchronization lock is the bytecode object of the class, which is equivalent to the code blocksynchronized(classname.class) {...} .
                    
                    Finally, to sum up:

                  • A lock for a synchronized block of code is an arbitrary object . As long as different threads are executing the same synchronized code block, this lock is set arbitrarily.
                  • The lock of a synchronized function is fixed by this . When it is necessary to synchronize with the logic in the synchronization function, the lock in the code block must be this.
                  • 静态同步函数的锁是该函数所属类的字节码文件对象。该对象可以用this.getClass()方法获取,也可以使用 当前类名.class 表示。

                  Guess you like

                  Origin http://10.200.1.11:23101/article/api/json?id=326945982&siteId=291194637