我的任务是创建一个程序,该程序具有:
- 类
客户端
- 类
门
- 类
博物馆
Client
使用Gate
类进入和离开Museum
。博物馆一次最多可接待 5 位客户。
当我在某个时候输入 1000 个 Clients
时,输出会给我不需要的数字。
示例输出:
Client (358) is leaving the Museum! number of customers: 2
Client (214) is entering the Museum! number of customers: 3
Client (214) is leaving the Museum! number of customers: 2
Client (73) is entering the Museum! number of customers: 5
Client (73) is leaving the Museum! number of customers: 5
Client (397) is entering the Museum! number of customers: 5
Client (76) is entering the Museum! number of customers: 6
----------------------------------------------------------------
Client (930) is entering the Museum! number of customers: 7
Client (930) is leaving the Museum! number of customers: 6
Client (308) is entering the Museum! number of customers: 6
Client (183) is entering the Museum! number of customers: 6
Client (183) is leaving the Museum! number of customers: 5
----------------------------------------------------------------
Client (647) is entering the Museum! number of customers: 7
Client (647) is leaving the Museum! number of customers: 6
----------------------------------------------------------------
Client (540) is entering the Museum! number of customers: 7
我预计客户将尝试在某个随机时间进入,当博物馆中有 5 个或更多客户时,他们将不得不等待其他线程结束其任务。
这是我的代码:
客户端.java
package client;
import gate.Gate;
import museum.Museum;
import java.util.Random;
public class Client extends Thread {
private static int id = 0;
private int clientID;
public Client() {
Client.id++;
this.clientID = id;
}
@Override
public void run() {
this.enterMuseum();
this.leaveMuseum();
}
///////////////////////////////////////////////////////////////////////////////////
private void enterMuseum() {
try {
Thread.sleep(new Random().nextInt(401) + 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
if (Gate.atomCustomer.get() < 5) {
Museum.getGate(0).enter(this);
break;
}
}
}
private void leaveMuseum() {
Museum.getGate(1).exit(this);
}
public int getClientId() {
return this.clientID;
}
////////////////////////////////////////////////////////////////////////////////////
}
门.java
package gate;
import client.Client;
import java.util.concurrent.atomic.AtomicInteger;
public class Gate {
public static AtomicInteger atomCustomer = new AtomicInteger();
public Gate() {
}
public void enter(Client client) {
if (atomCustomer.get() > 5) {
System.out.println("----------------------------------------------------------------");
}
atomCustomer.incrementAndGet();
System.out.println("Client (" + client.getClientId() + ") is entering the Museum!" +
" number of customers: " + atomCustomer.get());
}
public void exit(Client client) {
atomCustomer.decrementAndGet();
System.out.println("Client (" + client.getClientId() + ") is leaving the Museum!" +
" number of customers: " + atomCustomer.get());
}
}
博物馆.java
package museum;
import gate.Gate;
public class Museum {
private static Gate[] gate = new Gate[2];
public Museum() {
gate[0] = new Gate();
gate[1] = new Gate();
}
public static Gate getGate(final int numberOfGate) {
return Museum.gate[numberOfGate];
}
}
应用程序测试.java
import client.Client;
import museum.Museum;
import java.util.ArrayList;
import java.util.Scanner;
public class ApplicationTest implements Runnable {
private static int NUMBER_OF_CLIENTS = 0;
private static ArrayList<Client> listOfClients;
private static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
new Thread(new ApplicationTest()).start();
}
private static void init() {
while (NUMBER_OF_CLIENTS < 5) {
System.out.println("How many clients?( > 5): ");
NUMBER_OF_CLIENTS = sc.nextInt();
}
listOfClients = new ArrayList<>(NUMBER_OF_CLIENTS);
new Museum();
for (int i = 0; i < NUMBER_OF_CLIENTS; i++) {
ApplicationTest.listOfClients.add(new Client());
}
for (Client c : listOfClients) {
c.start();
}
}
@Override
public void run() {
ApplicationTest.init();
}
}
如有任何帮助,我将不胜感激。谢谢你的时间。问。
最佳答案
一些建议,不要使用公共(public)静态变量和静态方法,如 museum.getGate() 或原子客户计数器(这样更难理解谁使用了什么)。此外,Client 类应该与“计数器”逻辑完全隔离;也就是说,客户端应该简单地调用 gate.enter(),访问检查应该在 Gate 或 Museum 中完成。
然后是“关键”部分,您尝试在
中为客户端分配“许可” while (true) {
if (Gate.atomCustomer.get() < 5) {
//use museum.tryEnter() instead..
Museum.getGate(0).enter(this);
break;
}
}
这里,如果两个线程同时调用get(),它们都会发现客户的数量是eg。 4、都会进入(并发问题)。
确保只有一个客户端获得许可的一种方法是向某些同步方法添加嵌套调用,例如
private synchronized boolean tryEnter() {
if (counter<5) {
counter++;
return true;
}
else {
return false;
}
}
但是分配许可的更好方法是使用信号量(这样您甚至不需要那个繁忙的循环)。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html
关于Java多线程程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54855962/