【发布时间】:2015-06-21 13:45:45
【问题描述】:
我有这个练习:
开发多线程应用程序。 使用 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;
}
}
CashDesk 代码:
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
所以,如您所见,服务队列受到干扰。
当客户端 3 被服务时,客户端 6 必须开始服务,但客户端 50 这样做。当客户端 5 服务时,客户端 4 必须开始服务,但客户端 7 这样做。当 client7 服务时,我不知道为什么,但是 client6 移动到 cashDesk#1 并开始服务,尽管 client4 必须开始服务。
我是多线程新手,所以我需要一个建议,如何让我的应用程序正常工作
【问题讨论】:
-
您应该在问题中包含您的代码 - 至少是相关部分。指向 GIThub 的链接不是一个好主意,因为很少有人会费心去那里浏览。此外,您的问题似乎至少部分是机器翻译的,这使得它难以理解。我看到您在俄罗斯 SO 上也很活跃。在那里发帖不是更好吗?
-
@RealSkeptic 什么是难以理解的?我可以试着解释一下
-
我想你可以在
CashDesk.clients列表上得到一个ConcurrentModificationException:多个线程(Clients)可以同时改变这个列表。使用Collections.synchronizedList同步列表可能是个好主意。
标签: java multithreading concurrency reentrantlock