Java Synchronized keyword usage _java

Source: Internet
Author: User
Tags instance method

0. Pilot Problem code

The following code shows a counter in which two threads perform an additive operation on I, each performing 1 million times. The result we expect must be i=2000000. But when we do this more than once, we find that I is always less than 2000000. When two threads write to I at the same time, the result of one of the threads overwrites the other.

public class Accountingsync implements Runnable {
  static int i = 0;
  public void Increase () {
    i++;
  }
 
  @Override public
  Void Run () {for
    (int j = 0; J < 1000000; J + +) {
      increase ()}
  }
 
  public static void Main (string[] args) throws interruptedexception {
    Accountingsync accountingsync = new accountings Ync ();
 
    thread T1 = new Thread (accountingsync);
    Thread t2 = new Thread (accountingsync);
 
    T1.start ();
    T2.start ();
 
    T1.join ();
    T2.join ();
 
    System.out.println (i);
  }
}

To fundamentally solve this problem, we must ensure that multiple threads are fully synchronized when they operate on I. That is, when a thread writes to I, a B thread is not only not writable, it can not even read.

The role of 1.synchronized keywords

The function of keyword synchronized is to realize synchronization between threads. Its job is to lock up the synchronized code so that each time, only one thread enters the sync block, ensuring the security between threads. As in the code above, the i++ operation can only be executed at the same time by one thread.

Use of the 2.synchronized keyword

To lock a given object by locking it into a synchronized code block to obtain a lock on a given object

Direct action on an instance method: the equivalent of locking the current instance into a synchronized code block to obtain the current instance's lock (which requires that the same runnable instance be used when creating thread)

Direct action on static methods: equivalent to locking the current class to get the current class lock before entering the sync code block

2.1 Specify Object Lock

The following code applies synchronized to a given object. Here's a note that the given object must be static, otherwise we don't share the object with each new thread, and the meaning of the lock doesn't exist.

public class Accountingsync implements Runnable {
  final static object = new Object ();
 
  static int i = 0;
  public void Increase () {
    i++;
  }
 
  @Override public
  Void Run () {A for
    (int j = 0; J < 1000000; J + +) {
      synchronized (OBJECT) {
        increase ();
      }
    }
  }
 
  public static void Main (string[] args) throws interruptedexception {
    thread t1 = new Thread (new Accountingsync ()); 
    thread t2 = new Thread (new Accountingsync ());
 
    T1.start ();
    T2.start ();
 
    T1.join ();
    T2.join ();
 
    System.out.println (i);
  }
}
2.2 Direct Action on instance methods

The Synchronized keyword acts on an instance method, which means that the thread must obtain a lock on the current instance before entering the increase () method. This requires us to use the same Runnable object instance when creating the thread instance. Otherwise, Thread locks are not on the same instance, and there is no way to talk about the lock/sync problem.

public class Accountingsync implements Runnable {
  static int i = 0;
  Public synchronized void Increase () {
    i++;
  }
 
  @Override public
  Void Run () {for
    (int j = 0; J < 1000000; J + +) {
      increase ()}
  }
 
  public static void Main (string[] args) throws interruptedexception {
    Accountingsync accountingsync = new accountings Ync ();
 
    thread T1 = new Thread (accountingsync);
    Thread t2 = new Thread (accountingsync);
 
    T1.start ();
    T2.start ();
 
    T1.join ();
    T2.join ();
 
    System.out.println (i);
  }
}

Note the first three lines of the Main method, which describe the correct use of the keyword in the instance method.

2.3 Direct Action on static methods

The Synchronized keyword is used on the static method, as in the above example, two threads have to point to the same runnable method. Because the method block needs to request a lock for the current class, rather than the current instance, the thread can still be synchronized correctly.

public class Accountingsync implements Runnable {
  static int i = 0;
  public static synchronized void increase () {
    i++;
  }
 
  @Override public
  Void Run () {for
    (int j = 0; J < 1000000; J + +) {
      increase ()}
  }
 
  public static void Main (string[] args) throws interruptedexception {
    thread t1 = new Thread (new Accountingsync ()); 
   thread t2 = new Thread (new Accountingsync ());
 
    T1.start ();
    T2.start ();
 
    T1.join ();
    T2.join ();
 
    System.out.println (i);
  }
}

3. Wrong lock

From the above example, we know that if we need a counter application, we will naturally need to lock the counter to ensure the correctness of the data, so we might write the following code:

public class Badlockoninteger implements Runnable {
  static Integer i = 0;
  @Override public
  Void Run () {(
    int j = 0; J < 1000000; J + +) {
      synchronized (i) {
        i++;
      }
    }
  }
 
  public static void Main (string[] args) throws interruptedexception {
    Badlockoninteger badlockoninteger = new Badlock Oninteger ();
 
    thread T1 = new Thread (badlockoninteger);
    Thread t2 = new Thread (badlockoninteger);
 
    T1.start ();
    T2.start ();
 
    T1.join ();
    T2.join ();
 
    System.out.println (i);
  }
}

When we run the above code, we find that the output of I is very small. This indicates that the thread is not secure.

To explain this problem, start with the integer: In Java, an integer is a invariant object, and, like a string, an object cannot be modified once it is created. If you have a integer=1, then it will always be 1. What if you want this object to =2? Only one integer can be recreated. After each i++, the equivalent of calling the integer valueof method, we look at the integer valueof method of source code:

public static Integer valueof (int i) {
  if (i >= integercache.low && i <= integercache.high) return
    I Ntegercache.cache[i + (-integercache.low)];
  return new Integer (i);
}

Integer.valueof () is actually a factory method, and he will tend to return a new integer object and copy the value back to I;

So, we know the cause of the problem, since I have pointed to a new object between multiple threads because of i++, the thread may have loaded a different object instance each time it was locked. The solution is simple, using one of the 3 synchronize methods above to solve the problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.