一个容易产生死锁的线程协作

程序要做的功能是:模似生产者与消费者。代码如下:

public class AddEggThread implements Runnable {

	private Plate plate;
	private Object egg = new Object();
	public AddEggThread(Plate plate) {
		this.plate = plate;
	}
	
	@Override
	public void run() {
		plate.addEgg(egg);
	}
	
}

 

public class GetEggThread implements Runnable {

	private Plate plate;
	public GetEggThread(Plate plate) {
		this.plate = plate;
	}
	@Override
	public void run() {
		plate.getEgg();
	}

}

 

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Plate {

	private List<Object> eggs = new ArrayList<Object>();
	
	public  synchronized Object getEgg() {
		while(eggs.size() == 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Object egg = eggs.get(0);
		eggs.clear(); //清空
		notify(); // 唤醒阻塞队列的某线程进入就绪队列
		System.out.println("拿到鸡蛋");
		return egg;
	}
	
	public synchronized void addEgg(Object egg) {
		while (eggs.size() > 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		eggs.add(egg);
		notify();
		System.out.println("放入鸡蛋");
	}

	public static void main(String[] args) {
		Plate plate = new Plate();
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			exec.execute(new GetEggThread(plate));
			exec.execute(new AddEggThread(plate));
		}
		exec.shutdown();
	}
}

 执行程序,偶尔会产生死锁。回家后,在书上找到了解决问题的办法。先上代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Plate {

	private List<Object> eggs = new ArrayList<Object>();
	
	public  synchronized Object getEgg() {
		while(eggs.size() == 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Object egg = eggs.get(0);
		eggs.clear(); //清空
		notifyAll(); // 唤醒阻塞队列的某线程进入就绪队列
		System.out.println("拿到鸡蛋");
		return egg;
	}
	
	public synchronized void addEgg(Object egg) {
		while (eggs.size() > 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		eggs.add(egg);
		notifyAll();
		System.out.println("放入鸡蛋");
	}

	public static void main(String[] args) {
		Plate plate = new Plate();
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			exec.execute(new GetEggThread(plate));
			exec.execute(new AddEggThread(plate));
		}
		exec.shutdown();
	}
}

 认真比较两段代码的差异,不难发现:notify() 改成 notifyAll()。为什么使用notify会导致死锁呢?可以解释为:

notify() 只会唤醒一个等待的线程,被唤醒的线程不一定能获当前释放的锁。

使用notify()而不是notifyAll()是一种优化。使用notify时,在众多等待的任务中只有一个会被唤醒。因此如果你希望使用notify(),就必须保证被唤醒的是恰当的任务。

在实际的程序中,很难做到使用notify()只唤醒恰当的任务(只有两个线程的情况除外)。因此,更多的时候我们使用notifyAll()。notifyAll() 将唤醒“所有正在等待的任务”这个说法并不正确。只唤醒等待当前锁的线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值