我需要注册每个客户的订单 服务员只能在写下客户的所有请求后才能下达订单。 客户必须等到请求交付
我无法将客户端操作与服务员同步
我需要从我的对象Customer和Waiter同步每个动作 客户有1个订单 服务员有N个客户
要同步的动作序列在每个线程的“run”方法中实现
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 :(得分:0)
好吧,我必须说我很享受挑战......但我已经想到了这一点。我应该注意到我尝试了你的原始maxRounds,虽然它有效但有一个额外的客户可以通过队列的错误。 注意:我并不是说这是绝对做到这一点的最佳方式......也不一定是最优雅的,但它应该指向正确的方向。
我建议阅读BlockingQueues和扩展它的类。
主要打电话给沙龙:
public static void main(String[] args) {
Saloon saloon = new Saloon(100, 4, 50);
saloon.openBar();
}
Saloon Class:
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;
}
}