【发布时间】:2015-11-27 12:56:51
【问题描述】:
我正在使用 java 中的线程进行理发店模拟。理发店由一个有 n 把椅子的等候室和一个有几把理发椅的理发室组成。如果没有要服务的顾客,理发师就去睡觉。如果顾客进入理发店并且所有椅子都被占用,则顾客离开理发店。如果理发师很忙但有椅子可用,则顾客坐在其中一张空闲的椅子上。如果理发师睡着了,顾客会叫醒理发师。
到目前为止,我的代码运行良好(我认为)但有一个错误。在这里,客户在随机数毫秒后去理发店,并且可以去那里几次。问题是如果客户已经在理发店,在服务完成之前它不能再去那里,这意味着我需要阻塞客户线程直到理发师完成剪发,这就是我的代码失败的地方.我很确定它必须用 wait() 和 notify() 来完成,但是当我这样做时,我会弄乱其余的线程,可能我做错了什么。那么如何同步呢?在此先感谢:)
这是我的代码:
Main.java:
public class Main {
public static int tiempoSimulacion;
public static Logger logger = Logger.getLogger("ccia.labarberia");
static {
logger.setLevel(Level.OFF)
//logger.setLevel(Level.WARNING)
;}
public static void main(String[] args) throws InterruptedException {
Scanner sc = new Scanner(System.in);
int nBarberos = sc.nextInt();
int nClientes = sc.nextInt();
tiempoSimulacion = sc.nextInt();
Cliente.distribucionNormal = new NormalDistribution(sc.nextInt(),sc.nextInt());
Barbero.distribucionExponencial = new ExponentialDistribution(sc.nextInt());
Barberia b = Barberia.getBarberia(); // La Barberia sigue el patrón Singleton
Cliente.barberia = b;
Barbero.barberia = b;
b.setNumeroSillas(sc.nextInt());
sc.close();
Barbero[] barberos = new Barbero[nBarberos];
for (int i=1; i<=nBarberos; i++){
barberos[i-1] = new Barbero(i);
barberos[i-1].start();
}
b.setBarberos(barberos);
Thread[] clientes = new Thread[nClientes];
for (int j=1; j<=nClientes; j++){
clientes[j-1] = new Thread(new Cliente(j));
clientes[j-1].start();
}
Thread.sleep(tiempoSimulacion*1000);
for (int j=0; j<nClientes; j++){
clientes[j].interrupt();
}
for (int i=0; i<nBarberos; i++){
barberos[i].interrupt();
}
for (int j=0; j<nClientes; j++){
clientes[j].join();
}
for (int i=0; i<nBarberos; i++){
barberos[i].join();
}
}
}
Client.java:
public class Cliente extends Thread{
public static Barberia barberia;
public static NormalDistribution distribucionNormal;
private int id;
public Cliente (int id) {
this.id = id;
System.out.println("El cliente " + id + " se ha creado.");
}
public int identificador() {
return this.id;
}
@Override
public void run() {
try{
while (!Thread.interrupted()) {
try {
Thread.sleep((long)distribucionNormal.sample() );
} catch (IllegalArgumentException e) {
}
this.irABarberia();
}
}catch (InterruptedException e) {
System.out.println("El cliente " + this.id + " ha sido destruido.");
}
}
public void irABarberia() throws InterruptedException{
barberia.add(this);
}
}
理发师.java:
public class Barbero extends Thread{
private static final int OFFSET = 64;
public static Barberia barberia;
public static ExponentialDistribution distribucionExponencial;
private char id;
public Barbero(int i) {
this.id = (char) (OFFSET + i);
System.out.println("El barbero " + this.id + " se ha creado.");
}
public char identificador() {
return this.id;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
barberia.cortarPelo(this);
}
} catch (InterruptedException ex) {
System.out.println("El barbero " + this.id + " ha sido destruido.");
}
}
}
理发店.java:
public class Barberia {
private static Barberia mBarberia;
private static int numSillas;
private Barbero[] barberos;
LinkedList<Cliente> listaClientes;
protected Barberia() {
listaClientes = new LinkedList<Cliente>();
}
public static Barberia getBarberia() {
if (mBarberia == null) {
mBarberia = new Barberia();
}
return mBarberia;
}
public void setNumeroSillas(int sillas) {
numSillas = sillas;
}
public void setBarberos(Barbero[] b) {
this.barberos = new Barbero[b.length];
for (int i=0; i<this.barberos.length; i++) {
this.barberos[i] = b[i];
}
}
public void cortarPelo(Barbero barbero) throws InterruptedException{
Cliente cliente;
synchronized (listaClientes) {
while(listaClientes.size()==0) {
System.out.println("El barbero " + barbero.identificador() + " se pone a dormir.");
listaClientes.wait();
}
cliente = listaClientes.poll();
}
System.out.println("El barbero " + barbero.identificador() + " atiende al cliente " + cliente.identificador() + ".");
Thread.sleep((long)Barbero.distribucionExponencial.sample() );
System.out.println("El barbero " + barbero.identificador() + " ha cortado el pelo al cliente " + cliente.identificador() + ".");
}
public void add (Cliente cliente) throws InterruptedException{
System.out.println("El cliente " + cliente.identificador() + " llega a la barbería.");
synchronized (listaClientes) {
if(listaClientes.size() == numSillas) {
System.out.println("El cliente " + cliente.identificador() + " se marcha sin ser atendido.");
} else {
listaClientes.offer(cliente);
if(listaClientes.size()>0 && listaClientes.size() <= barberos.length){
listaClientes.notify();
} else {
System.out.println("El cliente " + cliente.identificador() + " se sienta en una silla de espera.");
}
}
}
}
}
【问题讨论】:
-
为什么不用join?
-
wait()和notify()是低级的原始操作,它们很难正确使用。请考虑改用更高级别的同步对象。阻塞队列可以是非常通用的。例如,您可以通过将代码写入队列中的令牌take()让客户端等待从椅子上站起来的许可。然后理发师线程可以通过将任何对象放入队列来授予客户端权限。
标签: java multithreading wait notify