我正在编写一个小程序来帮助我在java中学习一些多线程,而且我仍然坚持如何实现某些场景。
该程序模拟了一个加油站,里面还有一个咖啡馆。 我希望能够创建以下场景:
如何在这两种状态之间跳转?
到目前为止,我有这个:
Person类
public class Person implements Runnable {
private GasPump pump;
private Cashier cashier;
...
public void pumpGas() throws InterruptedException {
synchronized (this) {
pump.addCarToQueue(this);
wait();
}
synchronized (pump) {
sleep((long) (Math.random() * 5000));
pump.notify();
}
}
public void buyCoffee() throws InterruptedException {
synchronized (this) {
cashier.addCustomerToQueue(this); // standing inline
wait();
}
synchronized (cashier) {
sleep((long) (Math.random() * 5000)); // paying at cashier
cashier.notify();
}
}
...
}
GasPump类
public class GasPump implements Runnable {
private Queue<Person> cars;
...
@Override
public void run() {
while (gasStation.isOpen()) {
if (!cars.isEmpty()) {
Car firstCar = cars.poll();
if (firstCar != null) {
synchronized (firstCar) {
firstCar.notifyAll();
}
} else {
// ?
}
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
}
收银员班级
public class Cashier implements Runnable {
private Queue<Person> customers;
...
@Override
public void run() {
while(coffeeHouse.isOpen()){
if(!customers.isEmpty()){
Car firstCustomer = customers.poll();
if(firstCustomer != null){
synchronized (firstCustomer) {
firstCustomer.notifyAll();
}
}
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
}
答案 0 :(得分:3)
您应该避免使用wait
和notify
,因为很难正确有效地使用它们 - 请改用java.util.concurrent
中的类。
我会做什么:在boolean
:Person
和hasPumped
添加两个hasShopped
标记 - 一旦一个人抽出他们的汽油或商店,那么你设置适当的旗帜到true
。
将您的Queues
替换为BlockingQueues
(此处LinkedBlockingQueue
可能是合适的) - 这是一个线程安全的队列,您可以按顺序调用take
阻塞直到队列非空(而不是轮询,然后如果队列为空则休眠)。如果您更喜欢投票和睡觉,那么您可能希望使用ConcurrentLinkedQueue
,但我建议您在take
上使用BlockingQueue
。
将Person
添加到GasPump
和Cashier
个队列。通过take
或poll
将此人从队列中删除后,请检查其hasPumped
或hasShopped
标记,以确定是否需要执行任何其他操作,例如{ {1}}取得此人并Cashier
为真,因此无需询问hasPumped
他们是否希望继续在排队等候,因为他们已经完成了抽水。
如果此人选择退出队列,请在相应的队列上调用Person
。
当该人完成抽气时,如果他们的remove(person)
标志为假,则将他们放入收银队列,如果他们hasShopped
标志是他们的hasPumped
标志,他们同样将他们放入加油队列假的。
使用此实现时,您不需要任何synchronized
块或方法。
public class Person implements Runnable {
private GasPump pump;
private Cashier cashier;
private boolean hasPumped, hasShopped, readyToPump, readyToShop;
private Thread thread;
public void run() {
thread = Thread.getCurrentThread();
while(!hasPumped && !hasShopped) {
try {
readyToPump = false;
readyToShop = false;
if (!hasPumped)
pumpGas();
if(!hasShopped)
buyCoffee();
thread.sleep(FOREVER);
} catch (InterruptedException ex) {
// check flags to see what to do next
}
}
}
public void pumpGas() {
pump.addCarToQueue(this);
}
public void buyCoffee() {
cashier.addCustomerToQueue(this);
}
public void setReadyToPump() {
readyToPump = true;
thread.interrupt();
}
public void setReadyToShop() {
readyToShop = true;
thread.interrupt();
}
}
public class GasPump implements Runnable {
private BlockingQueue<Person> cars = new LinkedBlockingQueue<>();
@Override
public void run() {
while (gasStation.isOpen()) {
Person person = cars.take();
person.setReadyToPump();
}
// clean up persons in queue
}
}
public class Cashier implements Runnable {
private BlockingQueue<Person> customers = new LinkedBlockingQueue();
@Override
public void run() {
while(coffeeHouse.isOpen()){
Person person = customers.take();
person.setReadyToShop();
}
// clean up persons in queue
}
}