package com.java.mythread;/**
* 哲学家进餐问题的解决
* 缺点:线程调度不是先进先出调度或优先级调度
* */
public class Dining {
public static void main(String[] args){
Chopstick[] chops = new Chopstick[5];
Philosopher[] philos= new Philosopher[5];
for(int i= 0;i<5;i++){
chops[i] = new Chopstick();
}
for(int i= 0;i<5;i++){
philos[i] = new Philosopher(i,chops[i],chops[(i+1)%5]);
} for(int i= 0;i<5;i++){
philos[i].start();
}
}
}class Chopstick{
private boolean available;
public Chopstick(){
available = true;
}
public void takeUp(){
available = false;
}
public void putDown(){
available = true;
}
public boolean getStatus(){
return available;
}
}class Philosopher extends Thread{
public static int eatTime = 200, thinkTime = 300;
private Chopstick left,right;
int philo_num;
public Philosopher(int No,Chopstick lc,Chopstick rc){
left = lc;
right = rc;
philo_num = No;
//setDaemon(true);
}
synchronized public void requestChops(){
while(!left.getStatus() || !right.getStatus()){
System.out.println("哲学家"+philo_num+"正在等待……");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
left.takeUp();
right.takeUp();
}
synchronized public void returnChops(){
left.putDown();
right.putDown();
notify();
}
public void eat(){
System.out.println("哲学家"+philo_num+"正在进餐……");
try{
sleep(eatTime);
}catch(Exception e){}
}
public void think(){
System.out.println("哲学家"+philo_num+"正在思考……");
try{
sleep(thinkTime);
}catch(Exception e){}
}
public void run(){
while(true){
this.think();
this.requestChops();
this.eat();
this.returnChops();
}
}
}最后运行结果是:
哲学家0正在思考……
哲学家3正在思考……
哲学家2正在思考……
哲学家1正在思考……
哲学家4正在思考……
哲学家0正在等待……
哲学家4正在进餐……
哲学家3正在等待……
哲学家1正在等待……
哲学家2正在进餐……
哲学家4正在思考……
哲学家2正在思考……
哲学家4正在进餐……
哲学家2正在进餐……
无论等多长时间,只有哲学家2和哲学家4线程在运行,这掌握很费解啊。
代码中当某哲学家进餐完毕,执行this.returnChops();操作时,调用notify()函数后,不是所有等待进程同时竞争资源吗?为什么会只有两个线程一直运行,其他线程出于饥饿状态?改成notifyAll()函数,结果也一样。
哪位能给下指点啊?
* 哲学家进餐问题的解决
* 缺点:线程调度不是先进先出调度或优先级调度
* */
public class Dining {
public static void main(String[] args){
Chopstick[] chops = new Chopstick[5];
Philosopher[] philos= new Philosopher[5];
for(int i= 0;i<5;i++){
chops[i] = new Chopstick();
}
for(int i= 0;i<5;i++){
philos[i] = new Philosopher(i,chops[i],chops[(i+1)%5]);
} for(int i= 0;i<5;i++){
philos[i].start();
}
}
}class Chopstick{
private boolean available;
public Chopstick(){
available = true;
}
public void takeUp(){
available = false;
}
public void putDown(){
available = true;
}
public boolean getStatus(){
return available;
}
}class Philosopher extends Thread{
public static int eatTime = 200, thinkTime = 300;
private Chopstick left,right;
int philo_num;
public Philosopher(int No,Chopstick lc,Chopstick rc){
left = lc;
right = rc;
philo_num = No;
//setDaemon(true);
}
synchronized public void requestChops(){
while(!left.getStatus() || !right.getStatus()){
System.out.println("哲学家"+philo_num+"正在等待……");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
left.takeUp();
right.takeUp();
}
synchronized public void returnChops(){
left.putDown();
right.putDown();
notify();
}
public void eat(){
System.out.println("哲学家"+philo_num+"正在进餐……");
try{
sleep(eatTime);
}catch(Exception e){}
}
public void think(){
System.out.println("哲学家"+philo_num+"正在思考……");
try{
sleep(thinkTime);
}catch(Exception e){}
}
public void run(){
while(true){
this.think();
this.requestChops();
this.eat();
this.returnChops();
}
}
}最后运行结果是:
哲学家0正在思考……
哲学家3正在思考……
哲学家2正在思考……
哲学家1正在思考……
哲学家4正在思考……
哲学家0正在等待……
哲学家4正在进餐……
哲学家3正在等待……
哲学家1正在等待……
哲学家2正在进餐……
哲学家4正在思考……
哲学家2正在思考……
哲学家4正在进餐……
哲学家2正在进餐……
无论等多长时间,只有哲学家2和哲学家4线程在运行,这掌握很费解啊。
代码中当某哲学家进餐完毕,执行this.returnChops();操作时,调用notify()函数后,不是所有等待进程同时竞争资源吗?为什么会只有两个线程一直运行,其他线程出于饥饿状态?改成notifyAll()函数,结果也一样。
哪位能给下指点啊?
/**
* 哲学家进餐问题的解决
* 缺点:线程调度不是先进先出调度或优先级调度
* */
public class Dining {
public static void main(String[] args){
Chopstick[] chops = new Chopstick[5];
Philosopher[] philos= new Philosopher[5];
for(int i= 0;i<5;i++){
chops[i] = new Chopstick();
}
for(int i= 0;i<5;i++){
philos[i] = new Philosopher(i,chops[i],chops[(i+1)%5]);
}for(int i= 0;i<5;i++){
philos[i].start();
}
}
}class Chopstick{
private boolean available;
public Chopstick(){
available = true;
}
public void takeUp(){
available = false;
}
public void putDown(){
available = true;
}
public boolean getStatus(){
return available;
}
}class Philosopher extends Thread{
public static int eatTime = 200, thinkTime = 300;
private Chopstick left,right;
int philo_num;
public Philosopher(int No,Chopstick lc,Chopstick rc){
left = lc;
right = rc;
philo_num = No;
//setDaemon(true);
}
synchronized public void requestChops(){
while(!left.getStatus() || !right.getStatus()){
System.out.println("哲学家"+philo_num+"正在等待……");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
left.takeUp();
right.takeUp();
}
synchronized public void returnChops(){
left.putDown();
right.putDown();
notify();
}
public void eat(){
System.out.println("哲学家"+philo_num+"正在进餐……");
try{
sleep(eatTime);
}catch(Exception e){}
}
public void think(){
System.out.println("哲学家"+philo_num+"正在思考……");
try{
sleep(thinkTime);
}catch(Exception e){}
}
public void run(){
while(true){
this.think();
this.requestChops();
this.eat();
this.returnChops();
}
}
}
要知道,多个线程同时使用相同的资源才有同步问题
你这里的5个线程各自调用自己的方法
this.think();
this.requestChops();
this.eat();
this.returnChops();
跟线程和线程之间没有锁住同一个资源,你的wait和notify根本就没意义,只是自己对自己wait和notify,所以一旦进入wait,就一直等待不会被唤醒,就好像LZ的打印结果0和3,后面应该不会再出现0和3的任何打印了,因为一直停留在等待中了多个线程锁某个资源,应该synchronize(资源),然后调用 资源.wait() 资源.notify() 来达到等待和唤醒,或者在资源的方法上加上synchronized,这样wait或notify缺省就是资源的this.wait this.notify,这样才能达到同步的效果LZ再好好想想吧
现在修改哲学家类如下:
class Philosopher extends Thread{
public static int eatTime = 2000, thinkTime = 3000;
public static Chopstick[] chops = new Chopstick[5];//改动点儿
int philo_num;
public Philosopher(int No,Chopstick[] thechops){
for(int i= 0;i<5;i++){
chops[i] = thechops[i];
}
philo_num = No;
//setDaemon(true);
}
public void requestChops(){//改动点儿
synchronized(chops){
if(!chops[philo_num].getStatus()||!chops[(philo_num+1)%5].getStatus())
try {
chops.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("哲学家"+(philo_num+1)+"准备进餐……");
chops[philo_num].takeUp();
chops[(philo_num+1)%5].takeUp();
}
}
public void returnChops(){
synchronized(chops){//改动点儿
chops[philo_num].putDown();
chops[(philo_num+1)%5].putDown();
System.out.println("哲学家"+(philo_num+1)+"进餐完毕……");
chops.notifyAll();
}
}
}
现在已经能得出预期结果了:
哲学家1准备进餐……//可同时有两个线程访问资源
哲学家1正在进餐……
哲学家4准备进餐……//可同时有两个线程访问资源
哲学家4正在进餐……
哲学家1进餐完毕……
哲学家5准备进餐……//实现线程调度,没有出现饥饿现象
哲学家5正在进餐……
哲学家3准备进餐……
哲学家1正在思考……
哲学家2准备进餐……
哲学家2正在进餐……
哲学家3正在进餐……不知这样写,会不会还有什么不足之处,或者还有更好的更清晰的实现结构还请多多指教!
一位哲学家(假设1号)就餐时(访问资源),其前后两位(2和5) 因得不到筷子,会在"对象wait 池"里阻塞,另两位中的一位(假设3)能得到筷子,但不能得到同步锁,是在"对象lock池阻塞".(4号与2和5一样). 3号要等到1号释放锁后,才会进入就绪状态,可以运行.
此时2号或5号有一位会被 notify()唤醒,而进入对象lock 池. 一旦得到同步锁,即可运行(去吃饭).