JUC: 4_ 2. Concurrent collaboration model: producer consumer problem: if false wake-up, prevent false wake-up

How to alternate the communication between threads?

Threads A and B operate on the same variable numbe=0

/**
 * How to alternate the communication between threads?
 * Threads A and B operate on the same variable numbe=0
 * A++
 * B--
 * <p>
 * Question:
 * 1.It is safe when there are only two threads, one more + + and one more
 */
public class TestCondition {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    service.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

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

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

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

class ServiceImpl {
    private int number = 0;

    //++
    public synchronized void increment() throws InterruptedException {
//        if (number != 0) {
        while (number != 0) {
            //wait for
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "===>" + number);
        //Notify other threads + + to finish
        this.notifyAll();
    }

    //--
    public synchronized void decrement() throws InterruptedException {
//        if (number == 0) {
        while (number == 0) {
            //wait for
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "===>" + number);
        //Notify other threads -- done
        this.notifyAll();
    }
}

One + + one – to operate

When there are only two threads + +, – to operate, it is safe when there are only two threads

A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0

Two + + and two – threads operate on number at the same time

Two + + and two - threads operate on number at the same time, both of which have negative numbers

A===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
D===>-1
D===>-2
D===>-3
D===>-4
A===>-3

How did the problem occur: if and while

How does this negative number occur:
When > 1 and consumer notiyall appear, another producer who is wait ing grabs the lock and executes it++
When < 0 and consumer notiyall appear, another wait ing consumer grabs the lock and executes –

Two reasons

  1. object's wait() method releases the lock, which is different from sleep holding the lock. After releasing the lock, the second thread can obtain the lock
  2. If will judge only once. If judges, when the if method body is not executed completely, enter the lock and wait. When it is awakened again, get the lock again. Instead of making another if judgment, continue to execute the contents of if

When the if judgment is empty, the thread is blocked. At this time, the if judgment has been completed, and the thread will wake up and perform the remaining operations

When the while judgment is empty, the thread is blocked. At this time, the while loop is not completed. The while judgment will be repeated after the thread is awakened

Without using while spin, multiple consumers or producers will compete with each other to share resources

Why should object's wait() be judged by while?

public final void wait() throws InterruptedException

Causes the current thread to wait until another thread calls the notify() method or notifyAll() method of the object. In other words, the behavior of this method is like simply calling wait(0).
The current thread must own the display of the object. The thread releases ownership of this monitor and waits for another thread to notify the thread waiting for the object monitor to notify all by calling the notify method or notifyAll method. The thread then waits until it can regain ownership of the monitor and resume execution.

Like in a parametric version, interrupts and false wakes are possible, and the method should always be used in the loop:

  synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     } 

Keywords: Java Back-end Interview Multithreading JUC

Added by Erestar on Tue, 08 Mar 2022 02:01:46 +0200