2016-09-11 73 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

這與[The Sleeping Barber問題]非常相似(http://web.cecs.pdx.edu/~harry/Blitz/OSProject/p3 /SleepingBarberProblem.pdf),[wiki](https://en.wikipedia.org/wiki/Sleeping_barber_problem)。比喻是,服務員類似於理髮師,客戶任務從理髮改爲食品訂單。有一些細微的差異,但你可以從這裏開始(https://www.cs.helsinki.fi/u/kerola/rio/ohjeet/Java/semaphores/s06e-huhtamaki-merikanto-nevalainen/SleepingBarber.java)。 – vsnyc

回答

0

好吧,我必須說,我很喜歡的「運行」方法實施挑戰......但我已經明白了這一點。我應該注意到,我嘗試了您的原始maxRounds,雖然它的工作原理有一個額外的客戶可以通過隊列的錯誤。 注意:我不認爲這是做這件事絕對最好的方式......也不一定是最優雅的,但它應該指向你朝着正確的方向。

我建議閱讀關於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; 
    } 
} 

Order類:

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; 
    } 
} 

Customer類:

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

我不得不說,不是同步,圓印刷。它是無需重複的一輪,並在輪次前打印同一輪 另一件事,當我嘗試這個 新轎車(3,1,3)時,它會產生死鎖; – filipecampos

+0

不起作用=>新轎車(1,1,3); – filipecampos