产生原因
线程等待的条件应该使用while多次判断,而不是用if只判断一次,如本例中:同时存在多个消费者和生产者。
例如:生产者线程A生产完成之后,理想状态下是只唤醒一个处于wait状态的消费者B或者D去消费。但是实际情况是BD两个线程都会被唤醒,因为BD的业务判断条件使用的是if,就会导致BD同时消费。另外生产者线程C也会被唤醒,进行生产。所以应当用while进行多次判断,如果不符合条件,继续等待唤醒。
代码示例
一般线程类
public class ShamNotifyDemo {
public static void main(String[] args) {
DataOp dataOp = new DataOp();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
dataOp.add();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
dataOp.del();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
dataOp.add();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
dataOp.del();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"D").start();
}
}
class DataOp {
int number;
// 模拟生产者
public synchronized void add() throws InterruptedException {
// 不等于0的时候等待
if (number!=0) {
this.wait();
}
// 等于0的时候加
System.out.println(Thread.currentThread().getName()+"==>"+number++);
this.notifyAll();
}
// 模拟消费者
public synchronized void del() throws InterruptedException {
// 等于0的时候等待
if (number==0) {
this.wait();
}
// 不等于0的时候减
System.out.println(Thread.currentThread().getName()+"==>"+number--);
this.notifyAll();
}
}
JUC
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class JUCShamNotifyDemo {
public static void main(String[] args) {
DataOp2 dataOp = new DataOp2();
new Thread(()->{
for (int i = 0; i < 100; i++) {
dataOp.add();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
dataOp.del();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
dataOp.add();
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
dataOp.del();
}
},"D").start();
}
}
class DataOp2 {
int number;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 模拟生产者
public void add() {
lock.lock();
try {
// 不等于0的时候等待
if (number!=0) {
condition.await();
}
// 等于0的时候加
System.out.println(Thread.currentThread().getName()+"==>"+number++);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 模拟消费者
public void del(){
lock.lock();
try {
// 等于0的时候等待
if (number==0) {
condition.await();
}
// 不等于0的时候减
System.out.println(Thread.currentThread().getName()+"==>"+number--);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}