Java multithreading thread synchronization and locking issues

  • 2020-05-17 05:32:16
  • OfStack

1. Raise synchronization issues

The synchronization of threads is to prevent the data from being corrupted when multiple threads access one data object.

For example, two threads, ThreadA and ThreadB, both operate on the same object, Foo, and modify the data on the Foo object.


package cn.thread;

public class Foo {
  private int x = 100;

  public int getX() {
    return x;
  }

  public int fix(int y) {
    x = x - y;
    return x;
  }
}


package cn.thread;

public class MyRunnable implements Runnable {
  private Foo foo = new Foo();

  public static void main(String[] args) {
    MyRunnable run = new MyRunnable();
    Thread ta = new Thread(run, "Thread-A");
    Thread tb = new Thread(run, "Thread-B");
    ta.start();
    tb.start();
  }

  public void run() {
    for (int i = 0; i < 3; i++) {
      this.fix(30);
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " :  The current foo The object's x value = " + foo.getX());
    }
  }

  public int fix(int y) {
    return foo.fix(y);
  }

}

Operation results:

Thread-B: the x value of the current foo object = 40
Thread-A: the x value of the current foo object = 40
Thread-B: the x value of the current foo object = -20
Thread-A: the x value of the current foo object = -20
Thread-B: the x value of the current foo object = -80
Thread-A: the x value of the current foo object = -80

From the results, the output value is obviously unreasonable. This is due to two threads accessing the Foo object without control and modifying its data.

If you want to keep the results reasonable, you only need to achieve one goal, which is to restrict access to Foo to only one thread at a time. This ensures that the data in the Foo object is reasonable.

In the specific Java code, the following two operations need to be completed:

Identify the resource class Foo variable x as private;

Synchronize the code that changes the variables, using the synchronized keyword to synchronize methods or code.


package cn.thread;

public class Foo2 {
  private int x = 100;

  public int getX() {
    return x;
  }

  // Synchronized methods 
  public synchronized int fix(int y) {
    x = x - y;
    System.out.println(" thread "+Thread.currentThread().getName() + " Run over, reduce" " + y
        + " ", the current value is: " + x);
    return x;
  }
  
//  // Synchronized code block 
//  public int fix(int y) {
//    synchronized (this) {
//      x = x - y;
//      System.out.println(" thread "+Thread.currentThread().getName() + " Run over, reduce" " + y
//          + " ", the current value is: " + x);
//    }
//    
//    return x;
//  }

}

package cn.thread;

public class MyRunnable2 {

  public static void main(String[] args) {
    MyRunnable2 run = new MyRunnable2();
    Foo2 foo2=new Foo2();
    
    MyThread t1 = run.new MyThread(" thread A", foo2, 10);
    MyThread t2 = run.new MyThread(" thread B", foo2, -2);
    MyThread t3 = run.new MyThread(" thread C", foo2, -3);
    MyThread t4 = run.new MyThread(" thread D", foo2, 5);
    
    t1.start();
    t2.start();
    t3.start();
    t4.start();
  }
  
  class MyThread extends Thread {
    private Foo2 foo2;
    /** The current value */
    private int y = 0;
    
    MyThread(String name, Foo2 foo2, int y) {
      super(name);
      this.foo2 = foo2;
      this.y = y;
    }

    public void run() {
      foo2.fix(y);
    }
  }

}

Thread thread A ends run, reduce "10", current value is: 90
Thread thread C run ends, reduce "-3", current value is: 93
Thread thread B ends running, reduce "-2", current value is: 95
Thread thread D run ends, reduce "5", current value is: 90

2. Sync and lock

1. The principle of locking

Each object in the Java has a built-in lock.

When the program runs on the non-static synchronized synchronization method, it automatically gets the lock associated with the current instance (this instance) of the executing code class. Acquiring a lock on an object is also known as acquiring a lock, locking an object, locking on an object, or synchronizing on an object.

This object lock only becomes active when the program runs to an synchronized synchronized method or code block.

There is only one lock per object. So, if one thread acquires the lock, no other thread can acquire the lock until the first thread releases (or returns) the lock. This also means that no other thread can enter the synchronized method or code block on the object until the lock is released.

Releasing a lock is when the lock - holding thread exits the synchronized synchronized method or block of code.

There are several important points about locking and synchronization:

1) only methods can be synchronized, not variables and classes;

2) each object has only one lock; When it comes to synchronization, what should you know about synchronization? That is, on which object?

3) instead of synchronizing all the methods in a class, a class can have both synchronous and asynchronous methods.

4) if two threads want to execute the synchronized method in a class, and two threads use the same instance to call the method, only one thread can execute the method at a time, and the other one needs to wait until the lock is released. That is, if a thread acquires a lock on an object, no other thread can enter any of the synchronized methods in the class.

5) if a thread has synchronous and asynchronous methods, the asynchronous methods can be freely accessed by multiple threads without being restricted by locks.

6) when a thread sleeps, any locks it holds will not be released.

7) threads can acquire multiple locks. For example, if the synchronized method of one object is called in the synchronized method of another object, the synchronized lock of two objects is acquired.

8) synchronization damages concurrency and the scope of synchronization should be minimized. Synchronization synchronizes not only the entire method, but also one part of the code block in the method.

9) when using a synchronized block of code, you should specify which object to synchronize on, that is, which object's lock to acquire. Such as:


public int fix(int y) {
   synchronized (this) {
      x = x - y;
   }
   return x;
}

Of course, a synchronized method can also be rewritten as an asynchronous method, but it does exactly the same thing, for example:


public synchronized int getX() {
   return x++;
}

with


public int getX() {
   synchronized (this) {
      return x++;
   }
}

The effect is exactly the same.

3. Static method synchronization

To synchronize static methods, you need a lock for the entire class object, which is the class (XXX.class).

Such as:


public static synchronized int setName(String name){
   Xxx.name = name;
}


Is equivalent to


public static int setName(String name){
   synchronized(Xxx.class){
      Xxx.name = name;
   }
}

4. What happens if the thread can't get the lock

If a thread tries to enter a synchronized method and its lock is already occupied, the thread is blocked on the object. Essentially, a thread enters one of the pools of the object and must wait there until its lock is released and the thread becomes runnable or runnable again.

When considering blocking, 1 must pay attention to which object is being used for locking:

1. Threads calling non-statically synchronized methods on the same object will block each other. If there are different objects, each thread has its own lock on the object, and the threads do not interfere with each other.

2. The threads that call the statically synchronized methods in the same class will block each other; they are all locked on the same Class object.

3. Static and non-static synchronized methods will never block each other because the static method is locked on the Class object and the non-static method is locked on the Class object.

4. For synchronized code blocks, see what objects have been used for locking (synchronized). Threads that synchronize on the same object will block each other, and threads that are locked on different objects will never block each other.

5. When you need to synchronize

When multiple threads access mutually exclusive (interchangeable) data at the same time, the data should be synchronized to protect it and ensure that both threads do not modify and change it at the same time.

Non-static methods are usually used to access changeable data in non-static fields.

Static methods are usually used to access mutable data in static fields.

If you need to use a static field in a non-static method, or call a non-static method in a static field, the problem becomes very complex. It's beyond the scope of the SJCP test.

6. Thread safety class

A class is said to be "thread-safe" when it is well synchronized to protect its data.

Even thread-safe classes should be especially careful, because the threads that operate are still not necessarily safe.

7. Thread synchronization summary

1. The purpose of thread synchronization is to protect the destruction of resources when multiple threads access one resource.

2, thread synchronization method is achieved by locking, each object has only 1 lock, the lock is associated with a specific object, thread 1 once acquired the object lock, other threads access to the object can no longer access other synchronization methods of the object.

3. For static synchronization methods, the lock is for this class, and the lock object is the Class object of this class. The locking of static and non-static methods does not interfere with each other. One thread gets the lock, and when it accesses a synchronized method on another object in one synchronized method, it gets the two object locks.

4. For synchronization, it is crucial to be awake at all times to synchronize on which object.

5. To write thread-safe classes, it is necessary to make a correct judgment on the logic and security of multiple threads' competing access to resources, analyze the "atomic" operation, and ensure that other threads cannot access the competing resources during the atomic operation.

6. When multiple threads wait for an object lock, the thread that does not get the lock will block.

7. Deadlocks are caused by threads waiting for each other to lock. In practice, the probability of deadlock is very small. Really let you write a deadlock program, not 1 will be good, ha ha. However, once a deadlock occurs, the program will die.

The original link: http: / / www cnblogs. com/linjiqin p / 3208843. html


Related articles: