JAVA Basic Multithread synchronized Keyword

Keywords: Java

synchronized

Reference to blog:: http://www.cnblogs.com/skywang12345/p/3479202.html

synchronized

Summary

Each object in Java has and only has one lock associated with it. This lock becomes an internal lock. The internal lock is an exclusive lock (also known as mutex, a lock can only be held by one thread). The internal lock is implemented by synchronized keyword, which can be used to modify methods and code blocks. The synchronized modification method is called synchronized method, the modified static method is called synchronized static method, and the modified code block is called synchronized block.

synchronized locks are objects

Basic rules

  1. When a thread accesses a synchronized method or synchronized code block of an object, other threads can access the non-synchronized modified method and code block of that object.
  2. When a thread accesses a synchronized method or synchronized code block of an object, access to the synchronized method and code block of that object by other threads will be blocked.
  3. When a thread accesses a synchronized method or block of synchronized code for an object, other threads will block access to other synchronized methods and blocks of code for that object.

Verification Rule 1

public static void main(String[] args) {
        Inner inner = new Inner();
        new Thread(() -> {
            try {
            	//Executing synchronization methods
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
            	//Execution of asynchronous methods
                inner.commonMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner {

    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }

    public void  commonMethod() throws InterruptedException {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--commonMethod");
                Thread.sleep(100);
		}
    }

Implementation results:

Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-0--synMethod

Verification Rule 2

public static void main(String[] args) {
        Inner inner = new Inner();
        Inner inner2 = new Inner();

        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner {
    
    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }
}

Verification results

Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod

Verification Rule 3

public static void main(String[] args) {
        Inner inner = new Inner();
        Inner inner2 = new Inner();

        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        new Thread(() -> {
            try {
                inner.synBlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
}


class Inner {
    
    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }

    public void synBlock() throws InterruptedException {
    	//What you get is the lock on this object, which is the current access object.
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

Verification results:

Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod

If we replace this object locked in synBlock with another object

class Inner {
	private final Object obj = new Object();
    public void synBlock() throws InterruptedException {
        //synchronized (this) {
        synchronized (obj) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

The result of starting the main method at this point is asynchronous execution, because the acquired object locks are different, because the acquired object locks in synchronized (obj) are the obj object locks, and the acquired object locks in synchronized method are the this object locks.

Global Lock and Object Lock

Object Lock: Gets a lock that corresponds to a unique association of an object, and if the object is a singleton, it is also a global lock. For example, synchronized keywords acquired by non-static methods are object locks
Global Lock: This lock is for class objects. Everything in java is an object. Classes also have corresponding objects. For example, the lock obtained by synchronized static methods is a class object.

	public static void main(String[] args) {
        Inner inner = new Inner();
        new Thread(() -> {
            try {
                Inner.synStaticMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                inner.synBlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner{
    public synchronized static void synStaticMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synStaticMethod");
            Thread.sleep(100);
        }
    }
    public void synBlock() throws InterruptedException {
        synchronized (Inner.class) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

Operation result

Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock

Inner.synStaticMethod(); Calls the static synchronization method, obtains the lock corresponding to Inner class object, and obtains the same lock with synchronized (Inner.class), class object is globally unique, so the lock corresponding to class object is also called global lock.

Refer to an example from someone else's blog:

	public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}

Suppose that Something has two instances x and y. Analyse the locks acquired by the following four sets of expressions.

(01) x.isSyncA()and x.isSyncB()
(02) x.isSyncA()and y.isSyncA()
(03) x.cSyncA()and y.cSyncB()
(04) x.isSyncA()and Something.cSyncA()

(1) Can not be accessed at the same time, because the access is the synchronization lock of object x.
(2) It can be accessed at the same time because the synchronization lock of the same object is not accessed.
(3) It can't be accessed at the same time. The static method invoked by instantiated object is the same as the direct access by class name. However, it is not recommended to use instantiated object because it will increase the cost of compiler parsing.
(4) It can be accessed at the same time. x.isSyncA() accesses the synchronous lock of the x object, and Something.cSyncA() accesses the global lock.

The difference between synchronized synchronization method and code block

When synchronized modifies an ordinary (non-static) method, executing it requires a lock on the object that executes the method, which is often called this, so the effect of using synchronized modifier is the same as that of using synchronized modifier block to lock this object in the method. As shown in the following code

public synchronized void synMethod()  { 
	//Logic code
}

public void synBlock() {
	synchronized (this) {
	//Logic code
	}
}

When synchronized modifies a static method, the lock of the class object is obtained when executed, and the lock objects obtained by the following two methods are the locks corresponding to the class object.

	public synchronized static void synStaticMethod() throws InterruptedException {
        //Code logic
    }
    public void synBlock() throws InterruptedException {
        synchronized (Inner.class) {
            //Code logic
        }
    }

summary

Synchronized keyword access locks are object locks, which are the core of synchronized keyword access. To judge whether the locks can be executed asynchronously is to judge whether the locks accessed are the same.

Posted by lottos on Thu, 25 Apr 2019 11:45:36 -0700