“This is the 15th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
False awaken
Look at the wait() method in the OFFICIAL JDK documentation, and if the conditional method used to determine the wait is incorrect, there will be a false wait
Now we have A scenario where thread A and thread B execute alternately, where thread A and thread B operate on the same variable num = 0, thread A performs +1, and thread B performs -1
When there are only two threads to operate on, there is no problem
But when the number of threads increases to four two threads to add and two threads to subtract, there is a problem
As shown in the running result, numbers 2 and 3 prove that concurrency is not controlled. The reason is that when judging the waiting condition, if judgment is adopted in the code, and the two threads operating at the same time are judged only once, which is false wake up
If instead the while
Install the official documentation to solve this problem, change the condition in the code to while, check the result of the run successfully solved this problem
Lock implements producer-consumer issues
In the previous synchronized version juejin.cn/post/703006… It uses wait() and notify() to wait and notify
If you look at Lock’s interface documentation, you will find that instead of using wait and notify, you will find await() and signal()
Change the above scenario to be implemented with Lock
public class TestPc4 { public static void main(String[] args) { Data2 data = new Data2(); new Thread(() -> { for (int i = 0; i < 3; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 0; i < 3; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); new Thread(() -> { for (int i = 0; i < 3; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); new Thread(() -> { for (int i = 0; i < 3; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "D").start(); } } class Data2 { private Integer number = 0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public void increment() throws InterruptedException { lock.lock(); try { while (number ! = 0) {// condition. Await (); } number++; System.out.println(Thread.currentThread().getName() + "-->" + number); // Notify other threads +1 to complete condition.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void decrement() throws InterruptedException { lock.lock(); try{ while (number == 0) { condition.await(); } number--; Println (thread.currentThread ().getName() + "-->" + number); condition.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); }}}Copy the code
View the running result. The lock is successfully added
As a result, thread allocations are random. This is not much different from the synchronized implementation, but Condition is a post-synchronized method and should have some advantages. Condition allows thread A to notify thread B when it finishes executing, and thread B to notify thread C when it finishes executing
Condition realizes accurate notification awakening
Condition is used to control thread execution, where A completes B and B completes C
To realize the demo
public class TestCondition { public static void main(String[] args) { Data3 data3 = new Data3(); new Thread(() -> { for (int i = 0; i < 2; i++) { data3.printA(); } }, "A").start(); new Thread(() -> { for (int i = 0; i < 2; i++) { data3.printB(); } }, "B").start(); new Thread(() -> { for (int i = 0; i < 2; i++) { data3.printC(); } }, "C").start(); Class Data3 {private Lock Lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); private Integer number = 1; public void printA() { lock.lock(); Try {// Business judgment execution notification while (number! = 1) { condition1.await(); } System.out.println(Thread.currentThread().getName() + "-->AAAA"); B number = 2; condition2.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void printB() { lock.lock(); Try {// Business judgment execution notification while (number! = 2) { condition2.await(); } System.out.println(Thread.currentThread().getName() + "-->BBBB"); // Wake up number = 3; condition3.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void printC() { lock.lock(); Try {// Business judgment execution notification while (number! = 3) { condition3.await(); } System.out.println(Thread.currentThread().getName() + "-->CCCC"); // Wake up number = 1; condition1.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); }}}Copy the code
The results
By setting up different monitors for notification, you can see that A, B, and C are executed in sequence