Inter thread communication - Synchronized thread communication & false wake-up

1, Inter thread communication

There are two models of inter thread communication: shared memory {and} message passing. The following methods are implemented based on these two models.

When the thread start() method is called, it is scheduled by the operating system, and the execution order is not fixed.

If you want threads to execute in the required order, you need to communicate between threads.

 

2, Multithreaded programming steps (medium)

Step 1: create a resource class and create data and operation methods in the resource class;

Step 2: operate the method in the resource class
(1) judgment
(2) work
(3) Notice

Step 3: create multiple threads and call the operation methods of the resource class;

 

3, Example 1

4, Example 2

Requirements: there are two threads to operate on a variable with an initial value of 0. One thread adds 1 to the current value and the other thread subtracts 1 to the current value. The two threads alternately complete the effect. Inter thread communication is required.

  

Synchronized implementation:

//The first step is to create a resource class and define properties and operation methods
class Share {
    //Initial value
    private int number = 0;

    //+1
    public synchronized void incr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 0. If not, wait
        if (number != 0) {
            this.wait();
        }

        //2.Work: if number If the value is 0, then +1 operation
        number++;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();

    }

    //-1
    public synchronized void decr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 1. If not, wait
        if (number != 1) {
            this.wait();
        }

        //2.Work: if number If the value is 1, then -1 operation
        number--;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();
    }

}

public class ThreadDemo1 {

    public static void main(String[] args) {
        //The third step is to create multiple threads and call the operation methods of the resource class;
        Share share = new Share();

        //Create thread
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();
    }
}

 

 

5, False awakening problem

synchronized realizes multi-threaded notification waiting
For the case of printing 0 and 1 above, what happens if it is replaced by 4 threads?

1. Modify to four threads

//The first step is to create a resource class and define properties and operation methods
class Share {
    //Initial value
    private int number = 0;

    //+1
    public synchronized void incr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 0. If not, wait
        if (number != 0) {
            this.wait();
        }

        //2.Work: if number If the value is 0, then +1 operation
        number++;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();

    }

    //-1
    public synchronized void decr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 1. If not, wait
        if (number != 1) {
            this.wait();
        }

        //2.Work: if number If the value is 1, then -1 operation
        number--;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();
    }

}

public class ThreadDemo1 {

    public static void main(String[] args) {
        //The third step is to create multiple threads and call the operation methods of the resource class;
        Share share = new Share();

        //Create thread
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "CC").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "DD").start();
    }
}

 

2. Operation results

    

It can be found that the running result is not correct at this time.

3. Analyze the causes

Changing to 4 or more threads will lead to errors and false wake-up!

Reason: if judgment is used. If the judgment is effective, there will be no problem. Why is the judgment not effective?

Take a look at the wait() method description:

 

 

False wake-up:

    

Schematic diagram:

Normal conditions:

    

 

 

 

 

Four threads:

    

 

 

 

 

When num = 1, add one thread. After the thread comes in, it is judged that it does not meet the requirements, and it will be blocked here;
If another plus one thread obtains the execution right, the judgment will not match, and it will be blocked here at the same time;
When a minus one thread comes in and executes, it will wake up the two plus one threads at the same time,
When the execution of one plus one thread is completed, num=1, but at this time, it is if judgment and will not be judged again,
Another plus one thread will also add one, num=2, so there is a false wake-up.

 

4. Solutions

wait() should be used in the method body.
//The first step is to create a resource class and define properties and operation methods
class Share {
    //Initial value
    private int number = 0;

    //+1
    public synchronized void incr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 0. If not, wait
        while (number != 0) {
            this.wait();  //Where you sleep, you wake up
        }

        //2.Work: if number If the value is 0, then +1 operation
        number++;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();

    }

    //-1
    public synchronized void decr() throws InterruptedException {
        //The second step is to judge, work and inform
        //1.Judgment: number Whether the value is 1. If not, wait
        while (number != 1) {
            this.wait();
        }

        //2.Work: if number If the value is 1, then -1 operation
        number--;
        System.out.println(Thread.currentThread().getName() + "::" + number);

        //3.notice
        this.notifyAll();
    }

}

public class ThreadDemo1 {

    public static void main(String[] args) {
        //The third step is to create multiple threads and call the operation methods of the resource class;
        Share share = new Share();

        //Create thread
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "CC").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "DD").start();
    }
}

 

In order to prevent false wake-up, use while judgment
Note: be sure to pay attention to false wakeups between multiple threads

 

6, Multithreaded programming steps (Part 2)

Step 1: create a resource class and create data and operation methods in the resource class;

Step 2: operate the method in the resource class
(1) judgment
(2) work
(3) Notice

Step 3: create multiple threads and call the operation methods of the resource class;

Step 4: in order to prevent false awakening, use while judgment;

 

 

 

Keywords: JUC

Added by php noob on Wed, 19 Jan 2022 19:18:10 +0200