[JavaEE] synchronized monitoring lock volatile keywords wait and notify

Table of contents

synchronized monitoring lock:

1. Mutual exclusion

2. Reentrancy

Synchronized usage:

volatile :

usage of volatile: 

The difference between volatile and synchronized: 

wait and notify: 

The difference between wait and sleep (interview): 


Because we will have thread safety problems in the process of using multithreading. Then we can use these solutions to solve thread safety issues.

synchronized monitoring lock:

Solution 1: monitor lock

The synchronized keyword has the following characteristics:

1. Mutual exclusion

When the program enters the code block modified by the synchronized keyword, it is locked at this time. It is unlocked when the code block is executed. When one of our threads locks the object and another thread executes to the object, it will block and wait.

We can simply understand it as: the above toilet is an example here. When someone (a thread) enters the toilet (executed to the monitored lock object) to solve it, the door must be locked (that is, locked), and someone behind ( Another thread) also needs to go to the toilet (execute to the object), you need to wait outside the door (blocking treatment), until the person inside comes out (unlock), and then go in (re-acquire and lock).

2. Reentrancy

Synchronized is a reentrant lock. A reentrant lock means that the same thread locks the same object twice or more at the same time. If there is no problem and no bug is generated, it is a reentrant lock. If it can't run normally, it is a non-reentrant lock.

Synchronized usage:

1. Synchronized modified common methods:

    public synchronized void increase(){
        sum++;
    }

The lock object here is this 

2. Synchronized modified static method

public class SynchronizedDemo1 {
    private int sum=0;

    public synchronized static void fun(int a){
        a++;
    }
    
}

The lock object here is an object of the SynchronizedDemo1 class.

3. Synchronized modified code block

    public  void increase(){
        synchronized(this){
            sum++;
        }

    }

At this time, the lock object is still this.

Note: When using synchronized, you must pay attention to who the lock object is. Generally, there are this, class name.class (class object) and ordinary object variables. 

volatile :

Solution 2: volatile keyword

First of all, we need to be clear: volatile is a keyword used to solve memory visibility problems, and its Chinese meaning is volatile. This is to remind the compiler not to make claims when encountering this keyword.

usage of volatile: 

Modifier variable.

for example:

volatile public int flag=0;

Here is an example: the previous example summarizing memory visibility:

package MySynchronized;

import java.util.Scanner;

class MyCount{
    volatile public int flag=0;
}

public class SynchronizedDemo2 {
    public static void main(String[] args) {

        MyCount myCount=new MyCount();

        Thread t1=new Thread(()->{
            while(myCount.flag==0){

            }
            System.out.println("循环结束!");

        });

        Thread t2=new Thread(()->{
            Scanner scan=new Scanner(System.in);
            System.out.println("输入你要输入的数字:");
            int result=scan.nextInt();
            myCount.flag=result;

        });
        t1.start();
        t2.start();
    }
}

If we don't add the above volatile, this will happen:

Only adding volatile will normally display the result we want:

The difference between volatile and synchronized: 

synchronized guarantees atomicity, volatile does not guarantee atomicity, but memory visibility

wait and notify: 

Solution 3: wait and notify 

First of all, we need to know that threads are randomly scheduled during execution and executed preemptively, so we don't know the order in which they execute. But in our actual development, sometimes we want each thread to execute in a certain order. At this time, we need to use our wait and notify.

What wait has to do: make the thread currently executing the code block and wait, release the lock, and reacquire the lock after waiting for wake-up. 

What notify has to do: wake up the waiting thread

Conditions for wait to be woken up:

1. Other threads call the notify method of the object

2. The waiting time of wait is timed out

3. wait throws InterruptedException (another thread calls the interrupted method of the waiting thread)

Here we give an example of how to use 3 threads to print ABC in order:

package MySynchronized;

public class SynchronizedDemo3 {
    public static void main(String[] args) {

        Object loker1=new Object();
        Object loker2=new Object();
        Thread t1=new Thread(()->{
            System.out.println("A");
            //A打印完进行通知t2
            synchronized (loker1){
                loker1.notify();
            }
        });

        Thread t2=new Thread(()->{
            //B在A前面,所以让t2阻塞等待
            synchronized (loker1){
                try {
                    loker1.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("B");
            //打印B之后,进行通知
            synchronized (loker2){
                loker2.notify();
            }
        });
        //为保证ABC的顺序,所以我们要保证C要在B的后面
        //所以我们在打印C之前,要让它阻塞等待
        Thread t3=new Thread(()->{
            //阻塞等待,等待t2线程的通知
            synchronized (loker2){
                try {
                    loker2.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("C");
            System.out.println("打印正确!");
        });
        //这里有个细节要注意:如果t1比t2先执行了,那么t1中的通知就失去了作用,也就是说t2还没有排队等待呢,t1已经通知了,这个时候通知就没有用了
        //等到t2等待的时候,t1就没有等二次通知的机会了,所以要让t2先执行。
        t2.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        t1.start();
        t3.start();
    }
}

Pay special attention: the objects of wait and notify must be consistent!

notifyAll method: 

Similar to the notify function, it notifies the threads of the same object. But the slight difference is that notify randomly wakes up a blocked thread where the same object is located (assuming there are multiple threads), notifyAll wakes up all of them, and the rest compete. (The risk is high, not very useful, the above wait and notify are the key points!!!! )

The difference between wait and sleep (interview): 

In fact, wait and sleep are completely incomparable in theory, because one is used for communication between threads, and the other is used to block threads for a period of time. The only similarity is that both threads can give up execution for a period of time.

Differences: 1. wait needs to be used with synchronized, sleep does not need
           2. wait is the method of Object and sleep is the static method of Thread

 

Guess you like

Origin blog.csdn.net/m0_67995737/article/details/128873776