虚假唤醒
在使用condition.await();方法时,应将该方法放入循环中,避免虚假唤醒,
await()方法,线程等待,并且释放锁的资源,在其他线程调用notifyall方法,并且抢到资源后,继续执行后面的程序;
在使用if判断条件进行线程是否等待时,会有多个线程在此处等待,在其他线程进行唤醒的时候,在此处等待的两个线程会连续唤醒,执行后续的程序导致不符合预期,这个现象叫做虚假唤醒。 在唤醒线程后,需要进行一次判断条件是否满足,故需要将awite放在while循环中。
在api中会明确的指出将awite放入循环中。
public class TestThreadTest {
public static void main(String[] args) {
Clerk3 clerk3 = new Clerk3();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk3.shengchan();
}
}
}, "生产A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk3.xiaofei();
}
}
}, "消费B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk3.shengchan();
}
}
}, "生产C").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk3.xiaofei();
}
}
}, "消费D").start();
}
}
class Clerk3 {
private int product = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//生产
public void shengchan() {
lock.lock();
try {
while (product >= 10) {
System.out.println("商品已满,无法添加");
condition.await();
}
System.out.println(Thread.currentThread().getName() + "生产了一个商品" + ++product);
condition.signalAll();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
public void xiaofei() {
lock.lock();
try {
while (product <= 0) {
System.out.println("没有商品 无法消费");
condition.await();
}
System.out.println(Thread.currentThread().getName() + "消费了一个商品" + --product);
condition.signalAll();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}