java产生死锁的条件:
1.互斥条件。任务使用的资源中至少有一个是不能共享的;
2.至少有一个任务它必须持有资源且正在等待获取一个当前被别的任务持有的资源;
3.资源不能被任务抢占,任务必须把资源释放当作普通事件;
4.必须有循环等待,这时,一个任务等待其他任务所持有的资源,后者又在等待另一个任务所持有的资源,这样一直下去,直到有一个任务在等待第一个任务所持有的资源,使得大家都被锁住。
以上条件对于产生死锁缺一不可,而其中,最容易解决死锁问题的一个方式是使条件4不能满足。
1.[代码]筷子实体类
/**
* 筷子,使用一个boolean变量标识当前筷子是否已经被拿取
*/
public class Chopstick {
private boolean taken = false;
public synchronized void take() throws InterruptedException {
while (taken) {
wait();
}
taken = true;
}
public synchronized void drop() {
taken = false;
notifyAll();
}
}
2.[代码]哲学家类
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 哲学家,在run方法中随机的拿取左边和右边或右边和左边的筷子,如果拿到了一双筷子则开始吃饭
* 吃完之后哲学家开始思考一段时间,后又开始准备拿筷子吃饭
*/
public class Philosopher implements Runnable {
private Chopstick left;
private Chopstick right;
private final int id;
private final int ponderFactor;
private Random random = new Random(47);
private void pause() throws InterruptedException {
if (ponderFactor == 0) {
return;
}
TimeUnit.MICROSECONDS.sleep(random.nextInt(ponderFactor * 250));
}
public Philosopher(Chopstick left, Chopstick right, int id, int ponderFactor) {
this.left = left;
this.right = right;
this.id = id;
this.ponderFactor = ponderFactor;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
System.out.println(this + " thinking");
pause();
/**
* 如果这里不使用这种随机的先后拿取的方式,那么每个哲学家都是先拿取右边的筷子,
* 就有可能造成一种情况即所有的哲学家都持有右边的筷子,而左边的筷子则从来都拿不到
* 如果随机拿取左边或右边的筷子,那么就使得这里不会产生循环等待,也就不满足条件4
*/
if (random.nextBoolean()) {
System.out.println(this + " grabbing right");
right.take();
System.out.println(this + " grabbing left");
left.take();
} else {
System.out.println(this + " grabbing left");
left.take();
System.out.println(this + " grabbing right");
right.take();
}
System.out.println(this + " eating");
pause();
right.drop();
left.drop();
}
} catch (InterruptedException e) {
System.out.println(this + " exiting via interrupt");
}
}
@Override
public String toString() {
return "Philosopher " + id;
}
}
3.[代码]主程序
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 产生死锁的主程序,点击enter退出
*/
public class DeadLockingDiningPhilosophers {
public static void main(String[] args) throws Exception {
int ponder = 5;
int size = 5;
ExecutorService exec = Executors.newCachedThreadPool();
Chopstick[] chopsticks = new Chopstick[size];
for (int i = 0; i < size; i++) {
chopsticks[i] = new Chopstick();
}
for (int i = 0; i < size; i++) {
exec.execute(new Philosopher(chopsticks[i], chopsticks[(i + 1) % size], i, ponder));
}
System.out.println("Press 'Enter' to quit");
System.in.read();
exec.shutdownNow();
}
}