Java实现银行叫号系统:同步与互斥的应用
以下是一个可能的实现方案(使用Java语言):
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
enum UserType {
PUBLIC, VIP, ORDINARY
}
class User {
private final int number;
private final UserType type;
public User(int number, UserType type) {
this.number = number;
this.type = type;
}
public int getNumber() {
return number;
}
public UserType getType() {
return type;
}
}
class Bank {
private final int M;
private final Queue<User> publicQueue;
private final Queue<User> vipQueue;
private final Queue<User> ordinaryQueue;
private final Lock lock;
private final Condition publicCond;
private final Condition vipCond;
private final Condition ordinaryCond;
private int publicCounter;
private int vipCounter;
private int ordinaryCounter;
public Bank(int M) {
this.M = M;
publicQueue = new LinkedList<>();
vipQueue = new LinkedList<>();
ordinaryQueue = new LinkedList<>();
lock = new ReentrantLock();
publicCond = lock.newCondition();
vipCond = lock.newCondition();
ordinaryCond = lock.newCondition();
publicCounter = 0;
vipCounter = 0;
ordinaryCounter = 0;
}
public void takeNumber(User user) throws InterruptedException {
lock.lock();
try {
switch (user.getType()) {
case PUBLIC:
publicQueue.offer(user);
publicCond.signalAll();
break;
case VIP:
vipQueue.offer(user);
vipCond.signalAll();
break;
case ORDINARY:
ordinaryQueue.offer(user);
ordinaryCond.signalAll();
break;
}
System.out.println('User ' + user.getNumber() + ' (' + user.getType() + ') takes a number.');
} finally {
lock.unlock();
}
}
public void serve() throws InterruptedException {
lock.lock();
try {
while (true) {
if (!publicQueue.isEmpty()) {
User user = publicQueue.poll();
System.out.println('Counter ' + (++publicCounter) + ' serves user ' + user.getNumber() + ' (' + user.getType() + ').');
Thread.sleep((long) (Math.random() * 1000)); // 模拟服务时间
} else if (!vipQueue.isEmpty()) {
User user = vipQueue.poll();
System.out.println('Counter ' + (++vipCounter) + ' serves user ' + user.getNumber() + ' (' + user.getType() + ').');
Thread.sleep((long) (Math.random() * 1000));
} else if (!ordinaryQueue.isEmpty()) {
User user = ordinaryQueue.poll();
System.out.println('Counter ' + (++ordinaryCounter) + ' serves user ' + user.getNumber() + ' (' + user.getType() + ').');
Thread.sleep((long) (Math.random() * 1000));
} else {
if (publicCounter + vipCounter + ordinaryCounter >= M) {
System.out.println('All users have been served.');
return;
}
System.out.println('No user is waiting. Counters are idle.');
publicCond.await();
vipCond.await();
ordinaryCond.await();
}
}
} finally {
lock.unlock();
}
}
}
public class BankSystem {
public static void main(String[] args) {
Bank bank = new Bank(3);
for (int i = 1; i <= 10; i++) {
try {
if (i % 3 == 0) {
bank.takeNumber(new User(i, UserType.PUBLIC));
} else if (i % 4 == 0) {
bank.takeNumber(new User(i, UserType.VIP));
} else {
bank.takeNumber(new User(i, UserType.ORDINARY));
}
Thread.sleep((long) (Math.random() * 1000)); // 模拟取号间隔时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
bank.serve();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在这个实现方案中,银行类Bank有三个队列,分别存放对公用户、VIP用户和普通用户。takeNumber方法用于用户取号,将用户加入相应的队列中,并通知等待在相应条件上的服务员。serve方法用于服务员服务用户,按照优先级依次从三个队列中取出用户,并模拟服务时间。如果没有用户等待,则服务员等待在相应的条件上。当所有用户都被服务过后,服务员停止服务。
在main方法中,模拟了10个用户依次取号的过程,并启动一个服务员线程对用户进行服务。可以看到,服务员按照优先级依次服务用户,而且每个用户只被服务一次。
原文地址: https://www.cveoy.top/t/topic/nSKl 著作权归作者所有。请勿转载和采集!