虛假喚醒
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Seller seller = new Seller();
Productor productor = new Productor(seller);
Consumer consumer = new Consumer(seller);
new Thread(productor, "生產者A").start();
new Thread(consumer, "消費者B").start();
new Thread(productor, "生產者C").start();
new Thread(consumer, "消費者D").start();
}
}
// 銷售員
class Seller {
private int product = 0;
// 進貨
public synchronized void get() {
if (product >= 1) {
System.out.println("貨物已滿");
try {
// 對應Object中的 wait()
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + ++product);
// 對應Object中的notifyAll()
this.notifyAll();
}
// 銷售
public synchronized void sale() {
if (product <= 0) {
System.out.println("貨物賣完");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + --product);
this.notifyAll();
}
}
// 生產者
class Productor implements Runnable {
private Seller seller;
public Productor(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
seller.get();
}
}
}
class Consumer implements Runnable {
private Seller seller;
public Consumer(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
seller.sale();
}
}
}
解決虛假喚醒
對於Object.wait()方法,JDK開發文檔是這樣說的
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop(對於某一個參數的版本,實現中斷和虛假喚醒是可能的,而且此方法應始終在循環中使用):
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
一、使用synchronized關鍵字
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Seller seller = new Seller();
Productor productor = new Productor(seller);
Consumer consumer = new Consumer(seller);
new Thread(productor, "生產者A").start();
new Thread(consumer, "消費者B").start();
new Thread(productor, "生產者C").start();
new Thread(consumer, "消費者D").start();
}
}
// 銷售員
class Seller {
private int product = 0;
// 進貨
public synchronized void get() {
while (product >= 1) {
System.out.println("貨物已滿");
try {
this.wait(); // wait()方法應該總是使用在while裏面可以防止虛假喚醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + ++product);
this.notifyAll();
}
// 銷售
public synchronized void sale() {
while (product <= 0) {
System.out.println("貨物賣完");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + --product);
this.notifyAll();
}
}
// 生產者
class Productor implements Runnable {
private Seller seller;
public Productor(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
seller.get();
}
}
}
class Consumer implements Runnable {
private Seller seller;
public Consumer(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
seller.sale();
}
}
}
二、使用同步鎖
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Seller seller = new Seller();
Productor productor = new Productor(seller);
Consumer consumer = new Consumer(seller);
new Thread(productor, "生產者A").start();
new Thread(consumer, "消費者B").start();
new Thread(productor, "生產者C").start();
new Thread(consumer, "消費者D").start();
}
}
// 銷售員
class Seller {
private int product = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
// 進貨
public void get() {
lock.lock();
try {
while (product >= 1) {
System.out.println("貨物已滿");
try {
// 對應Object中的 wait()
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + ++product);
// 對應Object中的notifyAll()
condition.signalAll();
} finally {
lock.unlock();
}
}
// 銷售
public synchronized void sale() {
lock.lock();
try {
while (product <= 0) {
System.out.println("貨物賣完");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + --product);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
// 生產者
class Productor implements Runnable {
private Seller seller;
public Productor(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
seller.get();
}
}
}
class Consumer implements Runnable {
private Seller seller;
public Consumer(Seller seller) {
this.seller = seller;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
seller.sale();
}
}
}