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
- 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
- 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 }