Java案例分析

【案例8-5】 小朋友就餐问题

2024-10-25 12 0

简介 1.任务描述 一圆桌前坐着5位小朋友,两个人中间有一只筷子,桌子中央有面条。小朋友边吃边玩,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。但是,小朋友在吃饭过程中,可能会发生5个小朋友都拿起自己右手边的筷子,这样每个小朋友都因缺少左手边的筷子而没有办法吃饭。本案例要求编写一个程序解决小朋友就餐问题,使每个小朋友都能成功就餐。

【案例8-5  小朋友就餐问题

【案例介绍】

  1.任务描述

一圆桌前坐着5位小朋友,两个人中间有一只筷子,桌子中央有面条。小朋友边吃边玩,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。但是,小朋友在吃饭过程中,可能会发生5个小朋友都拿起自己右手边的筷子,这样每个小朋友都因缺少左手边的筷子而没有办法吃饭。本案例要求编写一个程序解决小朋友就餐问题,使每个小朋友都能成功就餐。

2.运行结果

运行结果如图8-1所示。

upfile

图8-1 运行结果

【案例目标】

l  学会分析“小朋友就餐问题任务实现的逻辑思路。

l  能够独立完成小朋友就餐问题程序的源代码编写、编译以及运行。

l  通过“小朋友就餐问题程序理解多线程安全问题的方式原因,并掌握如果解决多线程安全问题。

【案例思路】

(1)     查看运行结果分析后,每个小朋友相当于一个线程,所以先创建一个Philosopher()方法作为小朋友。

(2)     查看运行结果分析后,创建eating()方法作为小朋友吃饭时的线程,创建thinking()方法作为小朋友玩耍时的线程。

(3)     查看运行结果分析后,需要在获取筷子的方法Fork中先定义一个boolean类型的数组,代表5根筷子的使用情况;再使用synchronized线程锁来控制只有左右手的筷子都未被使用时,才允许获取筷子,且必须同时获取左右手筷子。

(4)     查看运行结果分析后,需要在释放左右手筷子的方法putFork中使用synchronized线程锁来释放筷子。

(5)     最后在Test测试类中调用5次以上方法,代表5位小朋友。

【案例代码】

小朋友就餐问题的程序代码实现如文件8-1所示。

文件8-1  Philosopher.java

 1   package chapter0805;

 2   /*每个小朋友相当于一个线程*/

 3   public class Philosopher extends Thread{

 4       private String name;

 5       private Fork fork;

 6       public Philosopher(String name,Fork fork){

 7           super(name);

 8           this.name=name;

 9           this.fork=fork;

 10      }

 11      public void run(){

 12          while(true){

 13              thinking();

 14              fork.takeFork();

 15              eating();

 16              fork.putFork();

 17          }

 18      }

 19      public void eating(){

 20          System.out.println("小朋友"+name+"在吃饭");

 21          try {

 22              sleep(1000);//模拟吃饭,占用一段时间资源

 23          } catch (InterruptedException e) {

 24              // TODO Auto-generated catch block

 25              e.printStackTrace();

 26          }

 27      }

 28      public void thinking(){

 29          System.out.println("小朋友"+name+"在玩游戏");

 30          try {

 31              sleep(1000);//模拟思考

 32          } catch (InterruptedException e) {

 33              // TODO Auto-generated catch block

 34              e.printStackTrace();

 35          }

 36      }

 37  }

 38  class Fork{

 39      /*5只筷子,初始为都未被用*/

 40      private boolean[] used={false,false,false,false,false};

 41      /*只有当左右手的筷子都未被使用时,才允许获取筷子,且必须同时获取左右手筷子*/

 42      public synchronized void takeFork(){

 43          String name = Thread.currentThread().getName();

 44          int i = Integer.parseInt(name);

 45          while(used[i]||used[(i+1)%5]){

 46              try {

 47                  wait();//如果左右手有一只正被使用,等待

 48              } catch (InterruptedException e) {

 49                  // TODO Auto-generated catch block

 50                  e.printStackTrace();

 51              }

 52          }

 53          used[i ]= true;

 54          used[(i+1)%5]=true;

 55      }

 56      /*必须同时释放左右手的筷子*/

 57      public synchronized void putFork(){

 58          String name = Thread.currentThread().getName();

 59          int i = Integer.parseInt(name);

 60          used[i]= false;

 61          used[(i+1)%5]=false;

 62          notifyAll();//唤醒其他线程

 63      }

 64  }

文件8-1中第3~18行代码封装一个小朋友的方法,第19~27行代码是封装了小朋友吃饭时的方法,第28~37行代码封装了小朋友玩耍时的方法,第38~64行代码封装了筷子使用情况的方法。

测试类的代码如文件8-2所示,调用5Fork代表5个小朋友。

文件8-2 Test.java

 1   package chapter0805;

 2   public class Test {

 3         public static void main(String []args){

 4               Fork fork = new Fork();

 5               new Philosopher("0",fork).start();

 6               new Philosopher("1",fork).start();

 7               new Philosopher("2",fork).start();

 8               new Philosopher("3",fork).start();

 9               new Philosopher("4",fork).start();

 10          }

 11  }

  

 


点赞 0

文章评论

欢迎您:

阿文博客

人生的价值,并不是用时间,而是用深度量去衡量的。——列夫·托尔斯泰

69 文章 1879 浏览 0 评论