False awaken
public class Tick {
public static void main(String[] args) {
Data date = new Data();
// Create 4 threads, two plus, two minus
new Thread(()->{
try {
for (int i=0; i<20; i++) date.increment(); }catch(InterruptedException e) { e.printStackTrace(); }},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch(InterruptedException e) { e.printStackTrace(); }}},"B").start();
new Thread(()->{
try {
for (int i=0; i<20; i++) date.increment(); }catch(InterruptedException e) { e.printStackTrace(); }},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch(InterruptedException e) { e.printStackTrace(); }}},"D").start(); }}class Data{
private int number=0;
public synchronized void increment(a) throws InterruptedException {
if(number! =0) // If there is more, wait
this.wait();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
this.notify();
}
public synchronized void decrement(a)throws InterruptedException{
if (number==0) // If not, wait
this.wait();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
this.notify(); }}Copy the code
Running results:
. C incr->1 A incr->2 C incr->3......Copy the code
The reason:
- When we use wait() in if, we can’t go wrong if we keep the ++, — order.
- If thread C acquires the lock while thread A is waiting and releases the lock after ++, thread A acquires the lock. Then the code after A directly waits does not make A conditional judgment, so it fails.
Solution:
Use while instead of if for example
public synchronized void decrement(a)throws InterruptedException{
while (number==0) // If not, wait
this.wait();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
this.notify();
}
Copy the code
Precise wake up single
Note for implementation of official document Single:
When this method is called, the implementation may (usually) require that the current thread save lock execution with the Condition must record this prerequisite and do anything if the lock is not held. Typically, an exception will be thrown if IllegalMonitorStateException.Copy the code
- Define multiple conditions and create multiple wait queues
- Condition. Single is used to wake up the longest waiting thread in the queue, which can be accurately woken up because there is only one thread waiting in multiple queues
public class TestCondistion {
public static void main(String[] args) {
Data3 date = new Data3();
// Set up the ABCD thread, call printA, B, C, D respectively
new Thread(()->{
try {
for (int i=0; i<20; i++) date.printA(); }catch(InterruptedException e) { e.printStackTrace(); }},"A").start();
// omit similar code}}class Data3{
private int number=0;
private Lock lock=new ReentrantLock();
// Create multiple conditions
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private Condition condition4 = lock.newCondition();
public void printA(a) throws InterruptedException {
lock.lock();
try{
while(number! =0)
condition1.await();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
Condition2 is the one that condition2 is waiting for the longest. Condition2 is the only one that condition2 is waiting for
condition2.signal();
}catch (Exception exception){
System.err.println("incr wrong");;
}finally{ lock.unlock(); }}public void printB(a)throws InterruptedException{
lock.lock();
try {
while ( number==0)
condition2.await();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
condition3.signal();
}catch (Exception ex){
System.err.println("decr wrong");
}finally{ lock.unlock(); }}public void printC(a)throws InterruptedException{
lock.lock();
try {
while( number! =0)
condition3.await();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
condition4.signal();
}catch (Exception ex){
System.err.println("incr wrong");
}finally{ lock.unlock(); }}public void printD(a)throws InterruptedException{
lock.lock();
try {
while ( number==0)
condition4.await();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
condition1.signal();
}catch (Exception ex){
System.err.println("decr wrong");
}finally{ lock.unlock(); }}}Copy the code
Running results:
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
Copy the code