Inter-thread communication

Threads are separate entities in the operating system, but these entities cannot become a whole without special treatment. Inter-thread communication is one of the necessary solutions to become a whole.

1. Wait/Notify Mechanism

    Waiting for notifications can be seen everywhere in reality. For example, when dining, the waiter has been waiting until the meal is initially ready, and once the meal is ready, the waiter is notified to serve the meal. This is waiting/notification.

    The implementation of waiting for notification is implemented using the wait method and the notify method.

    The role of the wait method makes the thread currently executing the code wait until it is notified or interrupted. Before calling the wait method, the thread must acquire the object-level lock of the object, that is, the wait method can only be called in a synchronized method or synchronized code block. After executing the wait method, the thread releases the object lock. Causes other threads waiting for the object lock to acquire the object lock.

    The notify method is also called in a synchronized method or synchronized code block, that is, before calling notify, the thread must also acquire the object lock on the object. When the notify method is executed, the current thread will not release the object lock immediately, but wait until the thread of the notify method finishes executing the program, that is, after exiting the synchornized code block, the current thread will release the object lock, and the thread in the wait state Only then can the object lock be acquired.

class FanXin{
    public static void main(String[] args) throws InterruptedException {
        Print p = new Print();
        Thread A = new Thread(){
            @Override
public void run() {
                p.f1();
}                        
        };
        A.setName("线程A");
        A.start();
        Thread.sleep(3000);
        Thread B = new Thread(){
            @Override
public void run() {
                p.f2();
}                        
        };
        B.setName("线程B");
        B.start();
    }
}
class Print{
    public void f1(){
        try {
            synchronized (this){
                System.out.println(Thread.currentThread().getName()+"开始");
                this.wait();
                System.out.println(Thread.currentThread().getName()+"结束");
            }
        }catch (Exception e){
            e.printStackTrace () ;
        }
    }
    public void f2(){
        try {
            synchronized (this){
                System.out.println(Thread.currentThread().getName()+"开始");
                this.notify();
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName()+"结束");
            }
        }catch (Exception e){
            e.printStackTrace () ;
        }
    }
}
As in the above code, thread A executes the f1 method, and thread B executes the f2 method. When thread A executes the wait method, it releases the object lock and waits for the notification of the object again, so it only prints one line, as shown in the following figure

    

When 3 seconds pass, thread B starts and executes the notify method. As I said just now, after the thread executes the notify method, the object lock will not be released immediately, but the lock will be released after the thread exits the synchronized code block. The following result is obtained


It can be seen that while thread B is sleeping, thread A does not acquire the object lock. When thread B exits the synchronized code block, thread A acquires the object lock and continues to execute the unfinished method. The result is as follows


The example just wakes up one thread. If there are other threads waiting, and the awakened thread has insufficient execution conditions, it does not execute. Now all threads are waiting for the release of the lock. At this time, if we wake up all threads and let them again To compete for locks, so that the probability of deadlocks is reduced.

The notifyAll method will wake up all threads and let them compete for locks again.

Let's make a little modification to the above code. The modified code is as follows

class FanXin{
    public static void main(String[] args) throws InterruptedException {
        Print p = new Print();
        Thread A = new Thread(){
            @Override
public void run() {
                p.f1();
}                        
        };
        A.setName("线程A");
        Thread B = new Thread(){
            @Override
            public void run() {
                p.f2();
            }
        };
        B.setName("线程B");
        Thread C = new Thread(){
            @Override
            public void run() {
                p.f3();
            }
        };
        C.setName("线程C");
        C.start();
        B.start();
        A.start();
    }
}
class Print{
    private int i = 1;
    public void f1(){
        try {
            synchronized (this){
                if (i!=1)
                    this.wait();
                System.out.println(Thread.currentThread().getName()+"开始");
                System.out.println(Thread.currentThread().getName()+"结束");
                this.notify();
                i=2;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void f2(){
        try {
            synchronized (this){
                if (i!=2)
                    this.wait();
                System.out.println(Thread.currentThread().getName()+"开始");
                System.out.println(Thread.currentThread().getName()+"结束");
                this.notify();
                i=3;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void f3(){
        try {
            synchronized (this){
                if (i!=3)
                    this.wait();
                System.out.println(Thread.currentThread().getName()+"开始");
                System.out.println(Thread.currentThread().getName()+"结束");
                this.notify();
                i=1;
            }
        }catch (Exception e){
            e.printStackTrace () ;
        }
    }
}
It can be seen that there are three threads, thread A executes f1, thread B executes f2, and thread C executes f3. The problem occurs, thread C grabs the CPU first, because the condition is not satisfied, so thread C waits. At this time, thread A gets CPU resources to execute f1, and notify immediately wakes up a thread. If thread C is woken up, and thread C is F3 is also executed, at this time

The value of i is 1, and thread B always does not run, and a deadlock occurs, as shown in the following figure


To solve the deadlock problem of this problem, the thread bar judgment is started, because the if judgment is only once, if the condition is not met this time, the thread will wait, but when it is woken up, this condition is useless, and we are not sure whether it is The thread starts executing from the waiting place, or executes from the judgment condition, so we change the if to while, so that when it is woken up, it is also necessary to judge whether the thread meets the condition. And we have to wake up more threads to compete for the lock again, which can avoid the deadlock problem above. The code is modified as follows

class FanXin{
    public static void main(String[] args) throws InterruptedException {
        Print p = new Print();
        Thread A = new Thread(){
            @Override
            public void run() {
                p.f1();
            }
        };
        A.setName("线程A");
        Thread B = new Thread(){
            @Override
            public void run() {
                p.f2();
            }
        };
        B.setName("线程B");
        Thread C = new Thread(){
            @Override
            public void run() {
                p.f3();
            }
        };
        C.setName("线程C");
        C.start();
        B.start();
        A.start();
    }
}
class Print{
    private int i = 1;
    public void f1(){
        try {
            synchronized (this){
                    while (i != 1)
                        this.wait();
                    System.out.println(Thread.currentThread().getName() + "开始");
                    System.out.println(Thread.currentThread().getName() + "结束");
                    this.notifyAll();
                    i = 2;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void f2(){
        try {
            synchronized (this) {
                    while (i != 2)
                        this.wait();
                    System.out.println(Thread.currentThread().getName() + "开始");
                    System.out.println(Thread.currentThread().getName() + "结束");
                    this.notifyAll();
                    i = 3;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void f3(){
        try {
            synchronized (this){
                    while (i != 3)
                        this.wait();
                    System.out.println(Thread.currentThread().getName() + "开始");
                    System.out.println(Thread.currentThread().getName() + "结束");
                    this.notifyAll();
                    i = 1;
            }
        }catch (Exception e){
            e.printStackTrace () ;
        }
    }
}
This avoids deadlocks.

Guess you like

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