问题描述
问题
车手来到公交车站等车。公交车到达时,所有等待的车手都调用boardBus,但是在公交车上车时到达的任何人都必须等待下一辆公交车。公交车可容纳50人;如果有 有超过50人在等待,有些人将不得不等待下一辆公共汽车。当所有等待的车手都登上车后,巴士便可以出发。如果在没有乘客的情况下到达公共汽车,则应立即出发。请注意,公交车和骑士将全天继续到达。假设公交车和骑手的到站时间分别以平均20分钟和30秒的指数分布。
对于这个问题,我需要一个并发程序,该程序可以满足Java中的互斥和同步,并提供清晰的解释。谁能帮我吗?
公共汽车
public class Bus {
public Bus() {
}
public void depart() {
System.out.println("I am departuring from the busstand....");
}
}
车手
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
public class Rider{
public void invokeBoard() {
System.out.println("I am boarding to the .... in the bus");
}
}
公交车站管理器
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class BusstandManager {
boolean isArrived;
int n;
Semaphore count_mutex;
Semaphore bus_mutex;
ArrayList<Rider> waiting_stage_queue;
ArrayList<Rider> bus_stand_queue;
public BusstandManager() {
this.isArrived = false;
this.n = 0;
this.count_mutex = new Semaphore(1);
this.bus_mutex = new Semaphore(1);
this.waiting_stage_queue = new ArrayList<>();
this.bus_stand_queue = new ArrayList<>();
}
public void putRider() {
Rider rider = new Rider();
try {
count_mutex.acquire();
if (n < 50 && !isArrived) {
n = n + 1;
bus_stand_queue.add(rider);
} else {
waiting_stage_queue.add(rider);
}
count_mutex.release();
} catch (InterruptedException e) {
System.out.println("Thread is suspended");
}
}
public void load_bus() {
try{
bus_mutex.acquire();
Bus bus = new Bus();
isArrived = true;
if (n != 0) {
for (Rider rider : bus_stand_queue) {
rider.invokeBoard();
}
n = 0;
}
bus.depart();}
catch (InterruptedException ie){
System.out.println("Thread is suspended");
}
}
public void execute() {
ExecutorService executorService = Executors.newFixedThreadPool(10);
// method reference introduced in Java 8
executorService.submit(this::putRider);
executorService.submit(this::load_bus);
// close executorService
executorService.shutdown();
}
}
用法
public class Main {
public static void main(String[] args) {
BusstandManager busstandManager = new BusstandManager();
busstandManager.execute();
}
}
线程未运行,因为我期望输出为
解决方法
此问题是并发编程中的常见问题。格兰特·哈钦斯(Grant Hutchins)为这个问题做了出色的解决方案。 他使用了3个信号灯和一个计数器来获取解决方案
waiting = 0;
mutex = new Semaphore(1)
bus = new Semaphore(0)
boarded = new Semaphore(0)
正在等待-登机区的骑手人数。
mutex-用于保护等待变量。
公共汽车-用于告诉骑手是否在法庭上乘坐公共汽车。
已登车-用于告知公交车乘客已登车。
总线过程代码
mutex . wait ()
n = min ( waiting,50)
for i in range ( n ):
bus . signal ()
boarded . wait ()
waiting = max ( waiting -50,0)
mutex . signal ()
depart ()
在这里,互斥锁用于锁定等待变量,因为每当总线到达时,任何人都无法增加等待时间。 n是等待的最小值,是50,因为如果我们有70个车手,那么我们只能让50个车手上车;如果我们有30个车手,那么我们可以让所有车手上车。在此最低条件下,我们仅可乘坐50名乘客。 然后,每辆公共汽车都会发出信号,告知到达者,以便驾驶员可以乘坐公共汽车。
50个车手登上公交车后,如果最初阶段的车手少于50人,则等待时间将设置为零,否则,由于50个车手登车,我们将减少50个车手。
然后我们释放互斥锁,以便新手能够来并增加其价值。
车手代码
mutex . wait ()
waiting += 1
mutex . signal ()
bus . wait ()
board ()
boarded . signal ()
rider线程在获得互斥锁时会等待互斥锁,它将增加等待状态,以告知它正在等待总线。
骑手线程正在等待总线,因此当总线到达总线时,骑手线程可以使用board方法。然后,骑手执行board()方法,这将表明骑手已登机。这样总线将再次发出信号以登上另一个线程。
我们还有另一种解决方案,它在此book中有所描述。 Java实现可在此github link
中找到`