我写了一个哲学家问题的解决方案。它正在运行,我在控制台上得到正确的输出但是println()
从未打印wait()
。请告诉我为什么。我在代码中指出了它。
解决方案意味着将类似与http://en.wikipedia.org/wiki/Dining_philosophers_problem#Resource_hierarchy_solution
相提并论public class Philosopher extends Thread {
String name;
// boolean je, czeka;
int nr;
Fork left, right;
public Philosopher(String name, int nr, Fork left, Fork right) {
this.nr = nr;
this.name = name;
this.left = left;
this.right = right;
System.out.println("NR " + nr +" "+ left + " " + right);
}
public void run() {
// while(true){
try {
Fork minF = Fork.min(left, right);
Fork maxF = Fork.max(left, right);
synchronized (minF) {
if (!minF.used) {
minF.used = true;
System.out.println("P" + nr + " took fork " + minF);
} else {
minF.wait();
minF.used = true;
System.out.println("I waited and took fork " + minF); //why it is never PRINTEDDD???
}
synchronized (maxF) {
if (!maxF.used) {
maxF.used = true;
System.out.println("P" + nr + " took fork "
+ maxF);
} else {
maxF.wait();
maxF.used = true;
System.out.println("I waited and took fork "+ maxF); //why it is never PRINTEDDD??
}
System.out.println("I am eating right now" + this);
eating();
System.out.println("P" + nr
+ " I have eaten I am giving back the forks");
minF.used = false;
System.out.println("P" + nr + " NOTIFY fork" + minF);
minF.notify();
maxF.used = false;
System.out.println("P" + nr + " NOTIFY fork" + maxF);
maxF.notify();
}
}
} catch (Exception e) {
}
// }
}
public void eating() throws InterruptedException {
int time = (int) (Math.random() * 2000);
for (int i = 0; i < 5; i++) {
System.out.println("P" + nr + " " + i);
Thread.sleep(time / 5);
}
}
public String toString() {
return "Philosopher " + nr;
}
public static void startPhilosophers(Philosopher[] f) {
for (int i = f.length - 1; i >= 0; i--) {
f[i].start();
}
}
public static void main(String[] args) {
Fork[] t = Fork.getArrayOfForks();
Philosopher[] f = { new Philosopher("philosopher 1", 1, t[0], t[4]),
new Philosopher("philosopher 2", 2, t[1], t[0]),
new Philosopher("philosopher 3", 3, t[2], t[1]),
new Philosopher("philosopher 4", 4, t[3], t[2]),
new Philosopher("philosopher 5", 5, t[4], t[3]), };
startPhilosophers(f);
}
}
public class Fork {
boolean used;
int nr;
public Fork(boolean used, int nr) {
this.used = used;
this.nr = nr;
}
@Override
public String toString() {
return "F" + nr;
}
public static Fork min(Fork l, Fork p){
if(l.nr < p.nr)
return l;
return p;
}
public static Fork max(Fork l, Fork p){
if(l.nr > p.nr)
return l;
return p;
}
public static Fork[] getArrayOfForks() {
Fork[] t = new Fork[5];
for (int i = 0; i < t.length; i++) {
t[i] = new Fork(false, (i + 1));
}
return t;
}
}
EXAMPLE output
NR 1 F1 F5
NR 2 F2 F1
NR 3 F3 F2
NR 4 F4 F3
NR 5 F5 F4
P5 took fork F4
P5 took fork F5
I am eating right nowPhilosopher 5
P4 took fork F3
P5 0
P2 took fork F1
P2 took fork F2
I am eating right nowPhilosopher 2
P2 0
P5 1
P2 1
P5 2
P2 2
P5 3
P2 3
P5 4
P2 4
P5 I have eaten I am giving back the forks
P5 NOTIFY forkF4
P5 NOTIFY forkF5
P4 took fork F4
I am eating right nowPhilosopher 4
P4 0
P2 I have eaten I am giving back the forks
P2 NOTIFY forkF1
P2 NOTIFY forkF2
P3 took fork F2
P1 took fork F1
P1 took fork F5
I am eating right nowPhilosopher 1
P1 0
P1 1
P4 1
P1 2
P4 2
P1 3
P4 3
P1 4
P4 4
P1 I have eaten I am giving back the forks
P1 NOTIFY forkF1
P1 NOTIFY forkF5
P4 I have eaten I am giving back the forks
P4 NOTIFY forkF3
P4 NOTIFY forkF4
P3 took fork F3
I am eating right nowPhilosopher 3
P3 0
P3 1
P3 2
P3 3
P3 4
P3 I have eaten I am giving back the forks
P3 NOTIFY forkF2
P3 NOTIFY forkF3
答案 0 :(得分:2)
synchronized (minF) {
if (!minF.used) { // always
minF.used = true;
}
...
minF.used = false;
minF.notify();
}
你正在对叉子进行同步,所以哲学家在检查它们是否正在使用时已经锁定了它们。
哲学家将fork.used
设置为true,但在离开synchronized块并释放锁之前将其设置为false。
编辑:根据要求,更新版本的代码。如果您使用已经执行的同步块,则无需自行执行管理:
synchronized (minF) {
synchronized (maxF) {
System.out.println("I am eating right now" + this);
eating();
System.out.println("P" + nr
+ " I have eaten I am giving back the forks");
}
}
如果你想明确地写出来,我会使用java.util.concurrent
类,并从Semaphore扩展Fork。您的代码如下所示:
分叉:
public class Fork extends Semaphore {
int nr;
public Fork(int nr) {
super(1); // can be handed out to only one person at a time
this.nr = nr;
}
...
哲学家:
minF.acquire();
maxF.acquire();
System.out.println("I am eating right now" + this);
eating();
System.out.println("P" + nr
+ " I have eaten I am giving back the forks");
maxF.release();
minF.release();
答案 1 :(得分:1)
flup已经回答了你的问题,但移动同步块是不够的;如果您希望将used
标记与wait
和notify
一起使用,则需要检查wait
循环中的条件,{{1}即使没有wait
,也可能会返回。
一种解决方案可能是:
notify
但是,请务必了解在此示例中,您的内容过于复杂。当您对锁具有订单时,您可以摆脱public class Demo
{
public static class Philosopher
extends Thread
{
String name;
int nr;
Fork left, right;
public Philosopher( String name, int nr, Fork left, Fork right )
{
this.nr = nr;
this.name = name;
this.left = left;
this.right = right;
System.out.println( "NR " + nr + " " + left + " " + right );
}
@Override
public void run()
{
// while ( true )
try {
Fork minF = Fork.min( left, right );
Fork maxF = Fork.max( left, right );
synchronized ( minF ) {
if ( ! minF.used ) {
minF.used = true;
System.out.println( "P" + nr + " took fork " + minF );
} else {
while ( minF.used )
// <- YOU NEED TO CHECK THIS IN A LOOP
minF.wait();
minF.used = true;
System.out.println( "I waited and took fork " + minF ); // why it is never PRINTEDDD???
}
}
synchronized ( maxF ) {
if ( ! maxF.used ) {
maxF.used = true;
System.out.println( "P" + nr + " took fork " + maxF );
} else {
while ( maxF.used )
// <- YOU NEED TO CHECK THIS IN A LOOP
maxF.wait();
maxF.used = true;
System.out.println( "I waited and took fork " + maxF ); // why it is never PRINTEDDD??
}
}
System.out.println( "I am eating right now" + this );
eating();
System.out.println( "P" + nr + " I have eaten I am giving back the forks" );
synchronized ( minF ) {
minF.used = false;
System.out.println( "P" + nr + " NOTIFY fork" + minF );
minF.notify();
}
synchronized ( maxF ) {
maxF.used = false;
System.out.println( "P" + nr + " NOTIFY fork" + maxF );
maxF.notify();
}
} catch ( Exception e ) {
// ignore
}
}
public void eating()
throws InterruptedException
{
int time = (int) ( Math.random() * 2000 );
for ( int i = 0; i < 5; i ++ ) {
System.out.println( "P" + nr + " " + i );
Thread.sleep( time / 5 );
}
}
public String toString()
{
return "Philosopher " + nr;
}
public static void startPhilosophers( Philosopher[] f )
{
for ( int i = f.length - 1; i >= 0; i -- ) {
f[ i ].start();
}
}
}
public static class Fork
{
boolean used;
int nr;
public Fork( boolean used, int nr )
{
this.used = used;
this.nr = nr;
}
@Override
public String toString()
{
return "F" + nr;
}
public static Fork min( Fork l, Fork p )
{
if ( l.nr < p.nr )
return l;
return p;
}
public static Fork max( Fork l, Fork p )
{
if ( l.nr > p.nr )
return l;
return p;
}
public static Fork[] getArrayOfForks()
{
Fork[] t = new Fork[ 5 ];
for ( int i = 0; i < t.length; i ++ ) {
t[ i ] = new Fork( false, ( i + 1 ) );
}
return t;
}
}
public static void main( String[] args )
{
Fork[] t = Fork.getArrayOfForks();
Philosopher[] f =
{ new Philosopher( "philosopher 1", 1, t[ 0 ], t[ 4 ] ), new Philosopher( "philosopher 2", 2, t[ 1 ], t[ 0 ] ),
new Philosopher( "philosopher 3", 3, t[ 2 ], t[ 1 ] ), new Philosopher( "philosopher 4", 4, t[ 3 ], t[ 2 ] ),
new Philosopher( "philosopher 5", 5, t[ 4 ], t[ 3 ] ), };
Philosopher.startPhilosophers( f );
}
}
并简化此操作:
used
答案 2 :(得分:0)
在你的代码中,fork-&gt; used属性总是在getArrayOfForks()方法中初始化为false,因此if条件将始终执行,而wait()在每个synchronized块上的else条件中。 / p>