我正在使用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);
}
}
Barber.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.");
}
}
}
Barbershop.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.");
}
}
}
}
}
答案 0 :(得分:-1)
您想要实现的目标,您可以使用同步功能。当多个线程正在同步同一个对象时,java会处理您自然寻求的行为:
当锁定空闲时,所有等待的线程都会尝试访问它。无需使用等待,加入或通知。
这是一个例子,实现你所谈论的行为:几个客户试图同时访问理发店的同一个席位。
理发店和主要计划:
public class BarberShop
{
// The main programm
public static void main(final String[] args)
{
// creating a Barbershopand its clients
final BarberShop shop = new BarberShop();
final BarberClient c1 = new BarberClient(shop, "Ian", 5);
final BarberClient c2 = new BarberClient(shop, "Chewy", 10);
final BarberClient c3 = new BarberClient(shop, "Luke", 3);
// all clients Try to go to the barbershop concurrently
c1.launchGoToBarberThread();
c2.launchGoToBarberThread();
c3.launchGoToBarberThread();
// Example output :
// Chewy Waiting for barbershop
// Luke Waiting for barbershop
// Ian Waiting for barbershop
// Chewy Entered Barber shop at Fri Nov 27 14:32:38 CET 2015
// Chewy Exiting Barber shop at Fri Nov 27 14:32:43 CET 2015
// Ian Entered Barber shop at Fri Nov 27 14:32:43 CET 2015
// Ian Exiting Barber shop at Fri Nov 27 14:32:45 CET 2015
// Luke Entered Barber shop at Fri Nov 27 14:32:45 CET 2015
// Luke Exiting Barber shop at Fri Nov 27 14:32:47 CET 2015
}
}
客户在商店同步:
import java.util.Date;
// client class implementing the concurrency behaviour around the seat.
public class BarberClient
{
// the shop we synchronize on. Let's say it has only one seat and we synchronize on this.
private final BarberShop barberShop;
private final String name; // a name
private final int beardSize; // the size of the beard to represent the time in the seat
private final Thread thread; // the thread that will actually be launched.
// constructor with name and beard size.
public BarberClient(final BarberShop pBarberShop,
final String pName,
final int pBeardSize)
{
barberShop = pBarberShop;
name = pName;
beardSize = pBeardSize;
// create the thread that just try to go to the barber...
thread = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
goToBarber();
} catch (final InterruptedException e)
{
e.printStackTrace();
}
}
});
}
// method concurrently trting to go to the shop
private void goToBarber() throws InterruptedException
{
System.out.println(name + "\tWaiting for barbershop");// display client is waiting
// Synchronize on the shop. It means you can seat only if nobody is on the seat. And waits for the seat
// being free.
synchronized (barberShop)
{
// We entered the synchronization block (= accessed to the seat).
// NOBODY else can access the seat while we are here.
// log enter, exit time, and wait for some time for the barber to do his job...
System.out.println(name + "\tEntered Barber shop at " + new Date(System.currentTimeMillis()));
Thread.sleep(500 * beardSize);
System.out.println(name + "\tExiting Barber shop at " + new Date(System.currentTimeMillis()));
}
// now we have leave the synchronization block (and the seat). Anybody can go.
}
// method to launch the thread.
public void launchGoToBarberThread()
{
thread.start();
}
}
我希望它能帮助您实施行为。 您可以在此处获得有关同步的一些信息:https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html