我正在编写一个小程序来帮助我学习 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();
}
}
}
}
}
...
}
最佳答案
您应该避免使用 wait
和 notify
,因为很难正确有效地使用它们 - 使用 java.util.concurrent
中的类> 相反。
我会做什么:向您的 Person
添加两个 boolean
标志:hasPumped
和 hasShopped
- 一次人抽他们的汽油或商店,然后您将适当的标志设置为 true
。
用 BlockingQueues
替换你的 Queues
(可能 LinkedBlockingQueue
在这里是合适的)——这是一个线程安全的队列,你可以调用take
以阻塞直到队列非空(而不是轮询然后在队列为空时 hibernate )。如果您更喜欢轮询和 hibernate ,那么您可能想要使用 ConcurrentLinkedQueue
代替,但我建议您在 BlockingQueue
上使用 take
代替。
将Person
添加到GasPump
和Cashier
队列。当此人通过take
或poll
从队列中移除时,然后检查其hasPumped
或hasShopped
标志以确定如果需要任何额外的操作,例如,如果 Cashier
接受了这个人并且 hasPumped
为真,那么就没有必要询问 Person
他们是否想继续在加油队列中等待,因为他们已经完成抽气。
如果此人选择退出队列,则在适当的队列上调用 remove(person)
。
当此人完成加油后,如果他们的 hasShopped
标志为假,则将他们放入收银员队列中,同样,如果他们的 hasPumped 已完成购物,则将他们放入加油队列中
标志为假。
此实现不需要任何同步
block 或方法。
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
}
}
关于java - 线程在 2 个队列中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18048703/