Mi tarea es crear un programa que tiene:
- Clase
Client
- Clase
Gate
- Clase
Museum
El Client
entra y salir de la Museum
usando la Gate
clase. El museo puede tener un máximo de 5 clientes a la vez.
Cuando me dicen que vamos de entrada 1000 Clients
, en algún momento, la salida me da números no deseados.
Resultado de muestra:
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
Estoy esperando que los clientes van a tratar de entrar en algún momento al azar, y cuando hay 5 o más clientes en el Museo, van a tener que esperar a que otro hilo al final se trata de tareas.
Aquí está mi código:
Client.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;
}
////////////////////////////////////////////////////////////////////////////////////
}
Gate.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());
}
}
Museum.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];
}
}
ApplicationTest.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();
}
}
Estaré agradecido por cualquier ayuda. Gracias por tu tiempo. Q.
Unas pocas sugerencias, no utilizan las variables públicas estáticas y métodos estáticos como museum.getGate () o el contador del cliente atómica (se hace más difícil de entender que lo utiliza). Además, la clase de cliente debe estar completamente aislada de la lógica "counter"; es decir, el cliente debe llamar simplemente gate.enter (), y las comprobaciones de acceso debe hacerse en cualquiera de las puertas o el Museo.
Luego está la parte "crítico", donde se intenta asignar un "permiso" a los clientes, en
while (true) {
if (Gate.atomCustomer.get() < 5) {
//use museum.tryEnter() instead..
Museum.getGate(0).enter(this);
break;
}
}
Aquí, si dos subprocesos llaman get () , al mismo tiempo , van a encontrar tanto que el número de clientes es, por ejemplo. 4, y ambos entrarán (tema concurrencia).
Una forma de asegurarse de que sólo un cliente obtiene el permiso es añadir una llamada anidada a algún método sincronizado como
private synchronized boolean tryEnter() {
if (counter<5) {
counter++;
return true;
}
else {
return false;
}
}
Sin embargo, una mejor manera de asignar permisos sería el uso de un semáforo (de modo que ni siquiera es necesario que bucle ocupado). https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html