我有这个练习:
开发一个多线程应用程序。使用 java.util.concurrent 机会。
不要使用:同步、BlockingQueue、BlockingDeque
所有希望访问资源的实体都必须是线程。利用 OOP 的机会。
我的任务是:
免费收银台。快餐店有几个收银台。客户在特定收银台排队,但如果那里的队列减少或消失,可能会去另一个收银台。
这是我的解决方案https://github.com/NikitaMitroshin/FreeCash
public class Restaurant {
private static Restaurant instance = null;
private static ReentrantLock lock = new ReentrantLock();
private String name;
private ArrayList<CashDesk> cashDesks;
private Restaurant(String name) {
this.name = name;
cashDesks = new ArrayList<>();
}
public static Restaurant getInstance(String name) {
lock.lock();
try {
if (instance == null) {
instance = new Restaurant(name);
}
} finally {
lock.unlock();
}
return instance;
}
public void addCashDesk(CashDesk cashDesk) {
cashDesks.add(cashDesk);
}
public String getName() {
return name;
}
public List<CashDesk> getCashDesks() {
return Collections.unmodifiableList(cashDesks);
}
}
客户端代码:
public class Client extends Thread {
private final static Logger LOG = Logger.getLogger(Client.class);
private Restaurant restaurant;
private CashDesk cashDesk;
private String name;
private int itemsInOrder;
public Client(Restaurant restaurant, int itemsInOrder, String name) {
this.restaurant = restaurant;
this.itemsInOrder = itemsInOrder;
this.name = name;
}
public String getClientName() {
return name;
}
public int getItemsInOrder() {
return itemsInOrder;
}
@Override
public void run() {
System.out.println("Client " + name + " comes to restaurant " + restaurant.getName());
this.cashDesk = chooseCashDesk();
System.out.println("Client " + getClientName() + " choosed the cashDesk#"+ cashDesk.getNumber());
cashDesk.addClient(this);
while (true) {
if (cashDesk.getLock().tryLock()) {
try {
cashDesk.serveClient(this);
} catch (ResourceException e) {
LOG.error("ResourceException!!! ", e);
} finally {
cashDesk.getLock().unlock();
break;
}
} else {
if (canChooseAnotherCashDesk()) {
cashDesk.removeClient(this);
}
}
}
cashDesk.removeClient(this);
System.out.println("Client " + getClientName() + " leaves restaurant");
}
private CashDesk chooseCashDesk(){
CashDesk result = restaurant.getCashDesks().get(0);
for (CashDesk cashDesk : restaurant.getCashDesks()) {
if(cashDesk.getClients().size() < result.getClients().size()) {
result = cashDesk;
}
}
return result;
}
private boolean canChooseAnotherCashDesk() {
CashDesk result = chooseCashDesk();
if(result.getClients().size() + 1 < cashDesk.getClients().size()) {
cashDesk = result;
cashDesk.addClient(this);
System.out.println("Client " + getClientName() + " moved to cashDesk#" + cashDesk.getNumber());
return true;
}
return false;
}
}
收银台代码:
public class CashDesk {
private ReentrantLock lock = new ReentrantLock();
private LinkedList<Client> clients;
private int number;
private int timeOfService;
public CashDesk(int number, int timeOfService) {
clients = new LinkedList<>();
this.number = number;
this.timeOfService = timeOfService;
}
public void serveClient(Client client) throws ResourceException {
System.out.println("Client "+client.getClientName() + " is serving on cashDesk#"+getNumber());
try {
client.sleep(timeOfService * client.getItemsInOrder());
} catch (InterruptedException e) {
throw new ResourceException("InterruptedException!!!", e);
}
System.out.println("Client "+client.getClientName() + " is served");
}
public List<Client> getClients() {
return Collections.unmodifiableList(clients);
}
public void addClient(Client client) {
clients.add(client);
}
public void removeClient(Client client) {
clients.remove(client);
}
public int getNumber() {
return number;
}
public ReentrantLock getLock() {
return lock;
}
}
跑步者代码:
public class RestaurantRunner {
public static void main(String[] args) {
Restaurant restaurant = Restaurant.getInstance("Mcdonalds");
CashDesk cashDesk1 = new CashDesk(1, 140);
CashDesk cashDesk2 = new CashDesk(2, 250);
restaurant.addCashDesk(cashDesk1);
restaurant.addCashDesk(cashDesk2);
new Client(restaurant, 100, "client50").start();
Random random = new Random();
for (int i = 1; i < 8; i++) {
int randNumbOfItems = random.nextInt(10) + 1;
Client client = new Client(restaurant, randNumbOfItems, "client"+i);
client.start();
}
}
}
我有问题。这就是我运行我的应用程序后得到的
Client client1 comes to restaurant Mcdonalds
Client client1 choosed the cashDesk#1
Client client1 is serving on cashDesk#1
Client client3 comes to restaurant Mcdonalds
Client client3 choosed the cashDesk#2
Client client3 is serving on cashDesk#2
Client client5 comes to restaurant Mcdonalds
Client client5 choosed the cashDesk#1
Client client6 comes to restaurant Mcdonalds
Client client6 choosed the cashDesk#2
Client client4 comes to restaurant Mcdonalds
Client client4 choosed the cashDesk#1
Client client50 comes to restaurant Mcdonalds
Client client50 choosed the cashDesk#2
Client client7 comes to restaurant Mcdonalds
Client client7 choosed the cashDesk#1
Client client2 comes to restaurant Mcdonalds
Client client2 choosed the cashDesk#2
Client client1 is served
Client client5 is serving on cashDesk#1
Client client1 leaves restaurant
Client client3 is served
Client client3 leaves restaurant
Client client50 is serving on cashDesk#2
Client client5 is served
Client client5 leaves restaurant
Client client7 is serving on cashDesk#1
Client client7 is served
Client client7 leaves restaurant
Client client6 moved to cashDesk#1
Client client6 is serving on cashDesk#1
Client client2 moved to cashDesk#1
Client client6 is served
Client client6 leaves restaurant
Client client2 is serving on cashDesk#1
Client client2 is served
Client client2 leaves restaurant
Client client4 is serving on cashDesk#1
Client client4 is served
Client client4 leaves restaurant
Client client50 is served
Client client50 leaves restaurant
因此,如您所见,服务队列受到干扰。
当为 client3 提供服务时,client6 必须开始服务,但 client50 这样做。当客户端 5 被服务时,客户端 4 必须开始服务,但客户端 7 这样做。当 client7 服务时,我不知道为什么,但是 client6 移动到 cashDesk#1 并开始服务,尽管 client4 必须开始服务。
我是多线程新手,所以我需要一个建议,如何让我的应用程序正常工作