2016-09-11 14 views
0

各顧客の注文を登録する必要があります ウェイターは顧客のすべてのリクエストを書き留めた後にのみ注文を送信できます。要求がJavaのスレッドを同期させる方法

を配信されるまで お客様は、私はウェイター

とクライアントのアクションを同期することはできません私は私のオブジェクトのお客様からの各アクションを同期させる必要があるとウェイター お客様が1オーダー ウェイターがNの顧客に

を持っている待機する必要があります

一連の動作は、私が楽しんだと言わなければならない

package room; 

import java.util.Random; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class Customer extends Thread { 

    private Random random; 
    private int id; 
    private static int ID; 
    private Order order; 
    private Waiter waiter; 

    public Customer(Waiter garcom) { 
     this.random = new Random(); 
     this.id = ID + 1; 
     Customer.ID++; 
     this.waiter = garcom; 
    } 

    @Override 
    public void run() { 
     orderRequest(); 
     waitOrder(); 
     receiveRequest(); 
     consumer(); 
    } 

    public synchronized void orderRequest() { 
     synchronized (this.order) { 

      int r = random.nextInt(3); 
      switch (r) { 
       case 0: 
        this.order.setOrder("Food"); 
        break; 
       case 1: 
        this.order.setOrder("Drink"); 
        break; 
       default: 
        this.order.setOrder("Help"); 
        break; 
      } 

      System.out.println(this.toString() + " request " + this.order.getOrder() + "to " + this.waiter.toString()); 

       this.order.notify(); 

      try { 
       this.order.wait(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex); 
      } 

     } 
    } 

    public synchronized void receiveRequest() { 

     synchronized (this.order) { 

      this.order.notify(); 

      try { 
       this.order.wait(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex); 
      } 

      System.out.println(this + " has received " + this.order + " from " + this.waiter); 
     } 
    } 

    private void waitOrder() { 
     synchronized (this.order) { 

      System.out.println(this + " consumer " + this.order); 

      this.order.notify(); 

      try { 
       this.order.wait(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex); 
      } 

     } 
    } 

    public synchronized void consumer() { 

     synchronized (this.order) { 

      System.out.println(this + " was consumed " + this.order); 

      this.order.notify(); 

      try { 
       this.order.wait(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex); 
      } 

     } 
    } 

    public void setOrder(Order order) { 
     this.order = order; 
    } 

    public Order getOrder() { 
     return order; 
    } 

    @Override 
    public String toString() { 
     return "Customer: " + id; 
    } 
} 

package room; 

public class Order { 

    private int orderNumber; 
    private static int ORDER_NUMBER = 0; 
    private Customer customer; 
    private String order; 

    public Order(Customer c) { 
     this.customer = c; 
     this.orderNumber = ORDER_NUMBER + 1; 
     this.customer.setOrder(this); 
     Order.ORDER_NUMBER++; 

    } 

    public String getOrder() { 
     return order; 
    } 

    public int getOrderNumber() { 
     return orderNumber; 
    } 


    public void setOrder(String order) { 
     this.order = order; 
    } 

    public Customer getCustomer() { 
     return customer; 
    } 

    @Override 
    public String toString() { 
     return "Order: " + order + " Nº " + orderNumber; 
    } 

} 

package room; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class Waiter extends Thread { 

    private Saloon saloon; 
    private int id; 
    private static int ID = 0; 
    private List<Order> orders; 

    public Waiter(Saloon bar) { 
     this.saloon = bar; 
     this.id = ID + 1; 
     Waiter.ID++; 
     this.orders = new ArrayList<>(); 

    } 

    @Override 
    public void run() { 

     while (saloon.isOpen()) { 

      registerOrder(); 
      deliveryRequest(); 

      saloon.round(); 
     } 
    } 

    public synchronized void registerOrder() { 

     for (Order order : orders) { 

      synchronized (order) { 

       order.notify(); 

       try { 
        order.wait(); 
       } catch (InterruptedException e) { 
        System.out.println(e.getMessage()); 
       } 
       System.out.println(this.toString() + " " 
         + "record " + order.toString() 
         + " to " + order.getCustomer()); 

      } 
     } 

    } 

    public synchronized void deliveryRequest() { 

     for (Order order : orders) { 

      synchronized (order) { 

       order.notify(); 

       try { 
        order.wait(); 
       } catch (InterruptedException ex) { 
        Logger.getLogger(Waiter.class.getName()).log(Level.SEVERE, null, ex); 
       } 

       System.out.println(this.toString() + " " 
         + "delivered " + order.toString() 
         + " to " + order.getCustomer()); 

      } 
     } 
    } 

    public synchronized void recordOrder(Order order) { 

     synchronized (orders) { 
      this.orders.add(order); 
     } 
    } 

    public List<Order> getOrders() { 
     return orders; 
    } 

    public Saloon getSaloon() { 
     return saloon; 
    } 

    @Override 
    public String toString() { 
     return "Waiter: " + id; 
    } 
} 

package room; 

import java.util.ArrayList; 
import java.util.List; 

public class Saloon { 

    private int maxRound; 
    private int numGarcons; 
    private volatile int round; 
    private int capacity; 
    private int customerCount; 
    private final List<Waiter> waiters; 

    public Saloon() { 
     this.waiters = new ArrayList<>(); 
     this.round = 1; 
    } 

    public Saloon(int customerCount, int waiterCount, 
      int capacity, int rounds) { 
     this(); 

     this.numGarcons = waiterCount; 
     this.customerCount = customerCount; 
     this.capacity = capacity; 
     this.maxRound = rounds; 

    } 

    /** 
    * Should it be call each round 
    */ 
    public void openBar() { 

     this.capacity = this.customerCount/this.capacity; 
     System.out.println("Round " + this.round); 

     for (int i = 0; i < this.numGarcons; i++) { 

      //Create a waiter 
      Waiter g = new Waiter(this); 

      for (int j = 0; j < this.capacity; j++) { 
       //create customer 
       Customer c = new Customer(g); 
       //an order 
       Order p = new Order(c); 
       //register order 
       g.recordOrder(p); 
       //call thread client 
       c.start(); 
      } 
      //waiter serves one client at a time 
      g.start(); 

      this.waiters.add(g); 
     } 

    } 

    public boolean isOpen() { 

     if (this.round < this.maxRound) { 
      return true; 
     } 
     return false; 
    } 

    public void round() { 
     this.round++; 
    } 
} 
+0

注文はウェイターのために設定されることはありませんように見えスタータのためのようにします。顧客の注文を作成してオーダーリストに設定しましたが、いつそれをウェイターに渡しますか? – Maxs728

+0

ちょうど私はコード全体を見ていると知っているし、修正を働いている – Maxs728

+0

これは[スリーピング・バーバーの問題](http://web.cecs.pdx.edu/~harry/Blitz/OSProject/p3 /SleepingBarberProblem.pdf)、[wiki](https://en.wikipedia.org/wiki/Sleeping_barber_problem)比喩は、Waiterは理髪師に似ており、CustomerタスクはHaircutからFood orderに変更されています。軽微な違いがありますが、[こちら](https://www.cs.helsinki.fi/u/kerola/rio/ohjeet/Java/semaphores/s06e-huhtamaki-merikanto-nevalainen/SleepingBarber.java)から始めることができます。 – vsnyc

答えて

0

オーケー各スレッドの「実行」の方法で実装された同期します挑戦...しかし、私はこれを考え出した。私はあなたのオリジナルのmaxRoundsを試したことに注意してください。そしてそれは動作しますが、1人の余分な顧客がキューからそれを作ることができるバグがあります。 注:私はこれを行うための絶対的な最善の方法であるとは主張していません...必ずしも最もエレガントではありませんが、正しい方向に向けるべきです。

BlockingQueuesについて読んで、それを拡張することをお勧めします。サロンへ

主なコール:

public static void main(String[] args) { 
    Saloon saloon = new Saloon(100, 4, 50); 
    saloon.openBar(); 
} 

サロンクラス:

package room; 

import java.util.ArrayList; 
import java.util.List; 

public class Saloon { 

    private volatile static int round; 
    private static int maxRound; 
    private int numWaiters; 
    private final List<Waiter> waiters; 
    private int customerMax; // current implementation doesn't need this but you could if you wanted 
    private volatile static boolean isOpen; 
    private OrderQueue<Order> orderQueue; // This is the creation of the queue 

    public Saloon() { 
     this.waiters = new ArrayList<>(); 
     Saloon.round = 1; 
    } 

    public Saloon(int customerMax, int numWaiters, int maxRounds) { 
     this(); 
     this.customerMax = customerMax; 
     this.numWaiters = numWaiters; 
     this.orderQueue = new OrderQueue<Order>(numWaiters); 
     Saloon.maxRound = maxRounds; 
    } 

    /** 
    * Should it be call each round 
    */ 
    public void openBar() { 
     System.out.println("Round " + round); 
     isOpen = true; 
     // Create all waiters at once outside the loop 
     for (int i = 0; i < this.numWaiters; i++) { 
      waiters.add(new Waiter(i + 1, orderQueue)); 
      waiters.get(i).start(); 
     } 
     int customersServed = 1; // Generating the id number here is a better choice IMO 
     while(isOpen) { 
      for (Waiter waiter : waiters) { 
       if (round >= maxRound) { 
        closeBar(); 
       } 
       if (waiter.isAvailable() && !waiter.isClockedOut()) { 
        // create customer 
        Customer customer = new Customer(customersServed++, waiter, orderQueue); 
        customer.start(); 
       } 
      } 
     } 
    } 

    /** 
    * A simple implementation to close the bar 
    */ 
    public void closeBar() { 
     isOpen = false; // ends the loop 
     int waitersFinished = 0; // used to check if all waiters stopped serving 
     while (waitersFinished < numWaiters) { 
      for (Waiter waiter : waiters) { 
       if (waiter.isAvailable()) { 
        synchronized (orderQueue) { 
         // if nothing is currently in the queue for the waiters 
         if (orderQueue.isEmpty()) { 
          orderQueue.done(); // close the queue 
          orderQueue.notify(); // notify the queue 
         } 
         waiter.clockOut(); // clockout the waiter could use better implementation 
         waitersFinished++; // increment waiters finished 
        } 
       } 
      } 
     } 
    } 

    public static boolean isOpen() { 
     return isOpen; 
    } 

    // I would not recommend using this... this is the source of the glitch 
    public synchronized static void round() { 
     if (round <= maxRound) { // only if reached maxRounds 
      System.out.println("Round " + round); 
      round++; 
     } 
    } 
} 

OrderQueueクラス:

package room; 

import java.util.concurrent.ArrayBlockingQueue; 

/** 
* 
* Note I did not create this.. tomasb did and I implemented it. 
* 
* @param <T> 
*/ 
public class OrderQueue<T> extends ArrayBlockingQueue<T> { 

    private static final long serialVersionUID = 1L; 
    private boolean done = false; 

    /** 
    * creates an order queue with a max capacity.. orders that can be concurrently handled 
    * @param capacity 
    */ 
    public OrderQueue(int capacity) { 
     super(capacity); 
    } 

    /** 
    * closes the while loop ending this orderqueue 
    */ 
    public void done() { 
     done = true; 
    } 

    public boolean isDone() { 
     return done; 
    } 

    /** 
    * May return null if producer ends the production after consumer has 
    * entered the element-await state. 
    */ 
    public T take() throws InterruptedException { 
     T el; 
     while ((el = super.poll()) == null && !done) { 
      synchronized (this) { 
       wait(); 
      } 
     } 

     return el; 
    } 
} 

注文クラス:

package room; 

public class Order { 

    private int orderNumber; 
    private static int ORDER_NUMBER = 0; 
    private String order; 

    public Order(int orderNumber) { 
     this.orderNumber = ORDER_NUMBER + 1; 
     this.orderNumber = orderNumber; 
    } 

    public String getOrder() { 
     return order; 
    } 

    public int getOrderNumber() { 
     return orderNumber; 
    } 

    public void setOrder(String order) { 
     this.order = order; 
    } 

    @Override 
    public String toString() { 
     return "Order: " + order + " Nº " + orderNumber; 
    } 
} 

顧客クラス:

package room; 

import java.util.Random; 

public class Customer extends Thread { 

    private int id; 
    private int orderNumber = 1; 
    private Order order; 
    private Waiter waiter; 
    private OrderQueue<Order> orderQueue; // This provides an esay way to pass objects 

    public Customer(int id, Waiter waiter, OrderQueue<Order> orderQueue) { 
     this.id = id; 
     this.waiter = waiter; 
     this.orderQueue = orderQueue; 
     waiter.addCustomer(this); 
     System.out.println("Customer: " + id + " sat at a table!"); 
    } 

    @Override 
    public void run() { 
     // Notice that wait has been removed. The orderQueue takes care of this. 
     orderRequest(); 
     receiveRequest(); 
     consumer(); 
     System.out.println("Customer: " + id + " has left satisfied!"); 
    } 

    public void orderRequest() { 
     // none of thie should be synchronized as it is local 
     order = new Order(orderNumber++); 

     Random random = new Random(); 
     int r = random.nextInt(3); 
     switch (r) { 
     case 0: 
      order.setOrder("Food"); 
      break; 
     case 1: 
      order.setOrder("Drink"); 
      break; 
     default: 
      order.setOrder("Help"); 
      break; 
     } 

     System.out.println(this.toString() + " request " + order.getOrder() + " to " + this.waiter.toString()); 

     // only the call to the orderqueue is synchronized 
     try { 
      synchronized (orderQueue) { 
       orderQueue.put(order); 
       orderQueue.notify(); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void receiveRequest() { 
     System.out.println(this + " has received " + this.order + " from " + this.waiter); 
    } 

    public void consumer() { 
     System.out.println(this + " was consumed " + this.order); 
    } 

    @Override 
    public String toString() { 
     return "Customer: " + id; 
    } 
} 

そして最後にウェイタークラス:

package room; 

public class Waiter extends Thread { 

    private int id; 
    private Order custOrder; 
    private Customer customer; 
    private volatile boolean isAvailable; 
    private volatile boolean clockOut; 
    private OrderQueue<Order> orderQueue; // The queue again 

    public Waiter(int id, OrderQueue<Order> orderQueue) { 
     this.id = id; 
     this.orderQueue = orderQueue; 
     System.out.println("Waiter " + id + " is ready to serve!"); 
    } 

    @Override 
    public void run() { 
     isAvailable = true; 
     while (!orderQueue.isDone() && !clockOut) { 
      if (isAvailable) { // this waiter is ready for a task 
       registerOrder(); 
       isAvailable = false; 
       synchronized (orderQueue) { // Synchronize this to the queue to prevent worse glitches 
        Saloon.round(); 
       } 
       if (custOrder != null) { // error checking 
        System.out.println(this.toString() + " record " + custOrder.toString() + " to " + customer); 
        deliveryRequest(); 
       } else { 
        isAvailable = true; 
       } 
      } 
     } 
    } 

    public synchronized void registerOrder() { 
     try { 
      custOrder = orderQueue.take(); // this is how you pull the order 
     } catch (InterruptedException e1) { 
      System.out.println(true); 
     } 
    } 

    public synchronized void deliveryRequest() { 
     System.out.println(this.toString() + " " + "delivered " + custOrder.toString() + " to " + customer); 
     isAvailable = true; 
    } 

    public void addCustomer(Customer customer) { // a easy way to add customers to the waiter after creation 
     this.customer = customer; 
     isAvailable = false; 
    } 

    public Order getOrder() { 
     return custOrder; 
    } 

    @Override 
    public String toString() { 
     return "Waiter: " + id; 
    } 

    public boolean isAvailable() { 
     return isAvailable; 
    } 

    public void clockOut() { 
     clockOut = true; 
    } 

    public boolean isClockedOut() { 
     return clockOut; 
    } 
} 
+0

私の親愛なる、最初に私はこのクラスのBlockingQueuesを知っていたと言いますが、このクラスの使用は制限されていました。 私はクラスArrayBlockingQueueなしでこれを作りたいと思います – filipecampos

+0

私は同期されていないと言わなければならない、丸い印刷。ラウンドが終了する前に同じラウンドを印刷する必要がなくラウンドを繰り返している もう1つ、これを試してもデッドロックが発生する 新しいサルーン(3,1,3); – filipecampos

+0

=>新しいSaloon(1,1,3);も動作しません。 – filipecampos

関連する問題