Java 如何使线程在不阻塞其他线程的情况下等待某个事件发生
我正在用java中的线程进行理发店模拟。理发店由一个带n把椅子的等候室和一个带几把理发椅的理发室组成。如果没有顾客,理发师就睡觉。如果顾客进入理发店,所有的椅子都被占满了,那么顾客就离开了理发店。如果理发师很忙,但椅子有空,那么顾客就坐在其中一张空椅子上。如果理发师睡着了,顾客就会叫醒理发师 到目前为止,我的代码运行良好(我认为),但有一个错误。在这里,客户在随机数毫秒后前往理发店,并且可以多次前往理发店。问题是,如果客户已经在理发店,在服务完成之前,它不能再去那里,这意味着,我需要阻止客户的线程,直到理发师完成理发,这就是我的代码失败的地方。我很确定这必须用wait()和notify()来完成,但是当我这样做的时候,我把其余的线程搞乱了,可能是我做错了什么。那么我如何同步呢?提前感谢:) 这是我的密码: Main.java:Java 如何使线程在不阻塞其他线程的情况下等待某个事件发生,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我正在用java中的线程进行理发店模拟。理发店由一个带n把椅子的等候室和一个带几把理发椅的理发室组成。如果没有顾客,理发师就睡觉。如果顾客进入理发店,所有的椅子都被占满了,那么顾客就离开了理发店。如果理发师很忙,但椅子有空,那么顾客就坐在其中一张空椅子上。如果理发师睡着了,顾客就会叫醒理发师 到目前为止,我的代码运行良好(我认为),但有一个错误。在这里,客户在随机数毫秒后前往理发店,并且可以多次前往理发店。问题是,如果客户已经在理发店,在服务完成之前,它不能再去那里,这意味着,我需要阻止客户的线
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();
}
}
}
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.");
}
}
}
}
}
公共类Barberia{
私人静态巴贝拉;
私有静态int numSillas;
私人巴贝罗[]巴贝罗;
LinkedList ListaClient;
受保护的巴伯里亚(){
listaClientes=newlinkedlist();
}
公共静态Barberia getBarberia(){
如果(mBarberia==null){
姆巴贝里亚=新巴贝里亚();
}
返回姆巴贝里亚;
}
公共空间集合数字(国际新罗){
numSillas=sillas;
}
公共空间(巴贝罗[]b){
this.barberos=新的Barbero[b.length];
对于(int i=0;i0&&listaClientes.size()您想要实现的目标,可以通过使用同步功能来实现。当多个线程同步同一对象时,java会自然处理您寻求的行为:
- 一次只能有一个线程访问同步锁
其他人等待
- 当锁空闲时,所有等待的线程都会尝试访问它。无需使用wait、join或notify
下面是一个例子,实现了您提到的行为:几个客户试图同时访问理发店的同一个座位
理发店和主要项目:
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();
}
}
我希望它能帮助你实现你的行为。
这里有一些关于同步的信息:为什么不使用join?wait()
和notify())是低级的原始操作,使用起来很复杂。考虑使用更高级的同步对象来代替。阻塞队列可以是多用途的。例如,您可以让客户等待通过从代码到()的权限从椅子上站起来。
队列中的令牌。然后barber线程可以通过put()向客户端授予权限将任何对象放入队列。否,synchronized
语句的目的是防止两个或多个线程同时访问相同的数据。如果希望一个线程等待另一个线程执行某项操作,则可以使用低级原语o.wait()
和o.notify()/o.notifyAll()
,但最好使用java.util.concurrent
包中定义的一个更高级别的同步对象(队列、信号量、屏障等)。
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();
}
}