需求:对一个数字0,两个线程进行操作,A线程操作10次+1,B线程操作10次-1。+-依次执行。代码如下:
package com.cp3.lock;
import org.junit.Test;
public class MyTest {
int index = 0;
/**
* 对index +1
*/
public synchronized void add() throws InterruptedException {
if(index == 1){
//如果index为1,则线程等待,释放锁
this.wait();
}
index++;
System.out.println(Thread.currentThread().getName() + "::" + index);
this.notifyAll();
}
/**
* 对index -1
*/
public synchronized void sub() throws InterruptedException {
if(index == 0){
//如果index为0,则线程等待,释放锁
this.wait();
}
index --;
System.out.println(Thread.currentThread().getName() + "::" + index);
this.notifyAll();
}
public static void main(String[] args) {
MyTest test = new MyTest();
new Thread(() -> {
for(int i = 0; i < 10; i++){
try {
test.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try{
test.sub();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
下图为运行结果,没毛病:
AB两个线程运行结果
接下来再加入两个线程,和A和B线程作用一样。共4个线程,看看效果:
public static void main(String[] args) {
MyTest test = new MyTest();
new Thread(() -> {
for(int i = 0; i < 10; i++){
try {
test.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try{
test.sub();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try{
test.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try{
test.sub();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
很明显,下图中不是我们期望的:
ABCD四个线程运行结果
因为Object.wait()出现了虚假唤醒:
这里如果用 if 的话,线程等待之后,下次被唤醒,直接不走if判断了,继续往下走。这就是虚假唤醒。应该将 if 换成 while 即可。
if(index == 1){
//如果index为1,则线程等待,释放锁
this.wait();
}