[JAVA core knowledge] 20-F.1: simple use of synchronized/wait/notify

Posted by scottbarry on Wed, 19 Jan 2022 01:19:13 +0100

1: Decorated code block

2: Modification method

Modified static method

Modified non static method

Inheritance of modifier methods

3: Use of wait and notify

Synchronization can be completed by modifying code blocks or methods with synchronized. There are several ways to use synchronized.

1: Decorated code block

When decorating a code block, you need to specify the lock object explicitly. When locked, all code blocks with the lock object as the lock

public void method1() {
	synchronized (lockObj) {
		// action1
	}
}

public void method2() {
	synchronized (lockObj) {
		// action2
	}
}

For example, in the above code, whether method1 and method2 belong to the same class or not, the synchronization code blocks in method1 and method2 use lockObj as the lock object, so they use the same lock, and action1 and action2 ensure synchronization. lockObj can be any instance that is not NULL.

2: Modification method

Synchronized modified methods only need to be modified with the synchronized keyword before the method, but the scope of locking modified static methods and non static methods is different.

Modified static method

public class SyncDemo {
    
    public synchronized static void method1() {
        // action1
    }
    
    public synchronized static void method2() {
        // action2
    }

}

As in the above code, the static methods method1 and method2 are modified respectively. When synchronized acts on a static method, it locks the Class instance. Because the Class instance is stored in the method area and shared globally, the static method lock is equivalent to a global lock, which will lock all static synchronization methods in SyncDemo.

Modified non static method

public class SyncDemo {
    
    public synchronized void method1() {
        // action1
    }
    
    public synchronized void method2() {
        // action2
    }

}

As in the above code, non static methods method1 and method2 are modified respectively. When synchronized acts on a non static method, it locks the object instance. For example, syncdemo s1 = new SyncDemo();SyncDemo s2 = new SyncDemo(); At this point S1 Method1 () and S1 Method2() is synchronized, but S1 Method1 () and S2 Method1() is out of sync.

Inheritance of modifier methods

Can synchronized inherit? The answer is that if the target method is written, the target method is overridden. If it is not overridden, it is overridden according to the method of the parent class. Next, you only need to remember what is the lock of synchronized modified static / non static methods, and you can well understand whether the two methods are synchronized in the scenario of inheritance relationship.

public class Pa {
    public synchronized void method1() {
        // action1
    }
    
    public static synchronized void method2() {
        // action2
    }
}
public class Cl extends Pa {
    If Cl If no method is overridden, then method2 The lock is Pa.class,method1 The lock is an instance object
    If Cl Override two methods, then method2 The lock is Cl.class,method1 The lock is still an instance object
    If Cl Rewrite removed synchronized Keyword, then both methods are out of sync
}

3: Use of wait and notify

The wait () method allows the thread holding the lock to temporarily give up the lock and block, wait for others to wake up, then re compete for the lock and continue to execute from the block. If no other thread wakes up, it will block all the time. The way to wake up is to wake up a blocked thread with notify(), and all blocked threads with notifyAll(). However, wait(), notify() and notifyAll() can only be used when the lock is held, that is, in the synchronization code, otherwise the IllegalMonitorStateException will be thrown. As for the reason, it involves the implementation principle of synchronized. If you are interested, you can take a look at this article Bowen.

public class SimSynchronized {


    public static void main(String[] args) {
        Object lock = new Object();
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("-------------------A Thread obtains lock---------------------");
                System.out.println("-------------------A Thread execution synchronization code block 1---------------------");
                try {
                    System.out.println("-------------------A Thread waiting---------------------");
                    lock.wait(); // Blocking wait
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("-------------------A Thread execution synchronization code block 2---------------------");
                System.out.println("-------------------A Thread wakes up other threads---------------------");
                lock.notify(); // awaken
            }
        }).start();

        try {
            // Sleep ensures that thread A obtains the lock first
            Thread.sleep(100);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("-------------------B Thread obtains lock---------------------");
                System.out.println("-------------------B Thread execution synchronization code block 1---------------------");
                System.out.println("-------------------B Thread wakes up other threads---------------------");
                lock.notify(); // awaken
                try {
                    System.out.println("-------------------B Thread waiting---------------------");
                    lock.wait(); Blocking wait
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("-------------------B Thread execution synchronization code block 2---------------------");
            }
        }).start();
    }
}

Operation results:

-------------------A Thread obtains lock---------------------
-------------------A Thread execution synchronization code block 1---------------------
-------------------A Thread waiting---------------------
-------------------B Thread obtains lock---------------------
-------------------B Thread execution synchronization code block 1---------------------
-------------------B Thread wakes up other threads---------------------
-------------------B Thread waiting---------------------
-------------------A Thread execution synchronization code block 2---------------------
-------------------A Thread wakes up other threads---------------------
-------------------B Thread execution synchronization code block 2---------------------

PS:
[JAVA core knowledge] series navigation [constantly updating...]
Previous navigation: 19: Various locks in JAVA
Next notice: 20: synchronized implementation principle and lock expansion: no lock or bias lock - lightweight lock - heavyweight lock. You can understand it after reading it
Welcome to

Topics: Java lock