Synchronized use of Java concurrency

Synchronized is a keyword in the Java language, read ['siŋkrənaizd], when it is used to modify a method or a code block, it can ensure that at most one thread executes the code at the same time.

1. Why does Java use synchronized?

Thread synchronization is to prevent data damage when multiple threads access a data object. To ensure that shared variables do not have concurrency problems, the code block that modifies the shared variables is usually locked with synchronized to ensure that only one thread is modifying the shared variables at the same time, thereby avoiding concurrency problems. Therefore, you need to keep in mind the word "shared". Only read and write access to shared resources needs to be synchronized. If it is not a shared resource, then there is no need for synchronization.

Second, the scope of synchronized modification

  1. Modified instance method > When multiple threads access the lock method of the same instance, there will be lock competition

  2. Modified static method > When multiple threads access the lock method of the class, there will be a lock competition

  3. Modified code block > When multiple threads access the same code block, there will be a competition problem

Three, synchronized synchronization lock object

Synchronized can be used to modify methods or code blocks. We can classify the acquired synchronization locks into the following three types:

  1. Instance object lock: Modified on ordinary methods (non-static methods); Modified this in code blocks, that is, synchronized (this) code blocks
  2. Class object lock: decorate on static methods; decorate class in code blocks, namely synchronized (X.class) code blocks
  3. Synchronized block non-current instance object lock: modify non-current instance objects in code blocks, such as the code for synchronized (object a) in class X

For these three different locks, the use of each other is not affected. For the same lock, there will be a lock race condition.

Fourth, the use of synchronized synchronization locks

For 1. the use of instance object locks:

  • All non-static synchronization methods use the same lock - the instance object itself, which means that if a non-static synchronization method of an instance object acquires the lock, other non-static synchronization methods of the instance object must wait for the method that acquires the lock to release The lock can only be acquired after the lock.
  • The instance object lock exists in the current instance, and the locks of different instance objects are not affected by each other.
  • The synchronized(this) code block acquires the lock corresponding to the instance. It uses the same lock as the non-static synchronized synchronization method, and there will be lock competition.
  • Instance locks and class object locks have no effect and will not block each other.

For the use of 2. class object locks:

  • For static synchronization methods, the lock is for this class, and the lock object is the Class object of that class.
  • All static synchronization methods use the same lock - the class object itself. If a static synchronization method acquires the lock, other static synchronization methods must wait for the method to release the lock before acquiring the lock.
  • Whether it is between static synchronization methods of the same instance object or between static synchronization methods of different instance objects, they all use the object lock of the same class, and there will be lock competition.
  • The synchronized(X.class) code block uses the object lock of the class Class, which will compete with the static synchronization method in the class. Lock race conditions can also occur in synchronized (X.class) blocks of code in multiple classes.

For 3. The use of non-current instance object locks in synchronized blocks:

  • For synchronized blocks, since the object lock is optional, there is a race condition only between synchronized blocks that use the same lock.
  • The object of the synchronization lock is based on the actual object rather than the object reference, so pay special attention when using it. In the scope of the lock, the synchronization lock loses the race condition due to the change of the actual object reference and the change of the lock object.

Five, synchronized use summary

Regarding the use of locks and synchronization, summarize the following points:

  1. Synchronization locks can only ensure the safety of shared variables by synchronizing methods, not synchronizing variables and classes.
  2. When referring to synchronization, it should be clear on what? That is, on which object is it synchronized?
  3. Instead of synchronizing all methods in a class, a class can have both synchronized and unsynchronized methods.
  4. For a thread with a race condition lock, one thread acquires the lock, and other threads block waiting for the release of the lock to acquire the lock.
  5. If a thread has synchronized and unsynchronized methods, the unsynchronized method can be freely accessed by multiple threads without being restricted by locks.
  6. When a thread sleeps, any locks it holds are not released.
  7. A thread can acquire multiple reentrant (synchronized) locks. For example, calling the synchronization method of another object in the synchronization method of one object acquires the synchronization lock of the two objects.
  8. Synchronization hurts concurrency and should be kept as small as possible. Synchronization can not only synchronize the entire method, but also a part of the code block in the method.
  9. When using synchronized code blocks, you should specify which object to synchronize on, that is, which object's lock to acquire
  10. When writing thread-safe classes, you need to always pay attention to making correct judgments on the logic and security of multiple threads competing to access resources, analyze "atomic" operations, and ensure that other threads cannot access them during atomic operations.

test

public class Service {

    public Service() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 构造方法");
    }

    static {
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 静态代码块");
    }

    private Object object1 = new Object();
    private Object object2 = new Object();

    synchronized public static void printA() {
        try {
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 进入方法A");
            Thread.sleep(3000);
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法A");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    synchronized public void printB() {
        try {
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 进入方法B");
            Thread.sleep(3000);
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法B");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void printC() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                + "在 " + System.currentTimeMillis() + " 进入方法C");
        try {
            synchronized (object1) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + "进入方法C--synchronized{X}");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 退出方法C-synchronized{X}");
            }
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法C");
        } catch (Exception e) {
            System.out.println(e);
        }
    }


    public void printD() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                + "在 " + System.currentTimeMillis() + " 进入方法D");
        try {
            synchronized (object2) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + "进入方法D--synchronized{X}");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 退出方法D-synchronized{X}");
            }
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法D");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void printE() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                + "在 " + System.currentTimeMillis() + " 进入方法E");
        try {
            synchronized (this) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 进入方法E--synchronized{this}");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 退出方法E-synchronized{this}");
            }
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法E");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public static void printF() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                + "在 " + System.currentTimeMillis() + " 进入方法E");
        try {
            synchronized (Service.class) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 进入方法F--synchronized{class}");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 退出方法F-synchronized{class}");
            }
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法F");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void printG() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                + "在 " + System.currentTimeMillis() + " 进入方法G");
        try {
            synchronized (Service.class) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 进入方法G--synchronized{class}");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                        + "在 " + System.currentTimeMillis() + " 退出方法G-synchronized{class}");
            }
            System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() 
                    + "在 " + System.currentTimeMillis() + " 退出方法G");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}

test:

/**
 * 0.synchronized同步方法、synchronized静态同步方法分别是用到的是实例锁,类锁,一个线程获取到synchronized同步方法的锁时,
 * 另一线程依然可以进入synchronized静态同步方法(实例锁,类锁两者不同,相互不影响
 * )
 * 1.synchronized同步方法,synchronized(this)都是对象锁,对于其他线程调用synchronized同步方法,synchronized(this)呈阻塞状态 </br>
 * 2.同一时间同一线程只有一个线程获取对象锁执行 </br>
 * <p>
 * 1.synchronized(非this)对象锁,对于非this如果是同一对象,两个线程同时只有一个可以获取该锁 </br>
 * 2.对象锁(synchronized同步方法 或 synchronized(this))、synchronized(非this)对象锁 两个线程同时执行,都可获得各自的锁 </br>
 * <p>
 * 1.synchronized修饰static方法与synchronized(X.class)作用一样
 *
 * @author fugaoyang
 */
public class TestRun {

    public static void main(String[] args) throws Exception {
        Service service = new Service();
        Thread threadA = new Thread("A") {
            @Override
            public void run() {
                service.printA();
            }
        };

        Thread threadB = new Thread("B") {
            @Override
            public void run() {
                service.printB();
            }
        };

        Thread threadC = new Thread("C") {
            @Override
            public void run() {
                service.printC();
            }
        };

        Thread threadD = new Thread("D") {
            @Override
            public void run() {
                service.printD();
            }
        };

        Thread threadE = new Thread("E") {
            @Override
            public void run() {
                service.printE();
            }
        };

        Thread threadF = new Thread("F") {
            @Override
            public void run() {
                service.printF();
            }
        };

        Thread threadG = new Thread("G") {
            @Override
            public void run() {
                service.printG();
            }
        };

        threadA.start();
        //threadB.start();
        //threadC.start();
        //threadD.start();
        //threadE.start();
        threadF.start();
        threadG.start();

        threadA.join();
        threadF.join();
        threadG.join();
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325362912&siteId=291194637
Recommended