我正在为一个列车系统建模,该系统有八个带有线程和监视器的站点。系统使用循环链表进行如下建模:
S2-S3-S4
/ \
S1 S5
>\ /
S8-S7-S6
链表的所有元素都属于Segment
类。有两种类型的Segment
s,FreeSegment
和Station
s。
当线程遍历链表时,系统在系统上并发运行。火车线程的代码如下:
public void runWithMonitors(boolean showMsgs) {
// This is the entry monitor
synchronized (entryPoint) {
try {
// Wait until the next segment is clear
// This loop guards against spurious wakeups as recommended
// by the official Java documentation
while (entryPoint.isOccupied()) {
entryPoint.wait();
}
} catch (InterruptedException ex) {
print("Services interrupted.", showMsgs);
}
}
// Run this code indefinitely
while (true) {
// This is the current segment monitor
// Only one train can ever occupy this segment
// Take note of the current segment
Segment currSegmentMonitor = currSegment;
synchronized (currSegmentMonitor) {
// Take this spot
currSegment.setIsOccupied(true);
currSegment.setTrainInside(this);
// If this segment is a station, load and unload passengers
if (currSegmentMonitor instanceof Station) {
// Open doors and allow passengers to get off and on
alightPassengers(showMsgs);
loadPassengers(showMsgs);
}
// Notify this train's observer that its position has changed
trainObserver.update(dispatcher, showMsgs);
// Is it okay to proceed?
try {
// Wait until the next segment is clear
// This loop guards against spurious wakeups as recommended
// by the official Java documentation
while (nextSegment.isOccupied()) {
currSegmentMonitor.wait();
}
} catch (InterruptedException ex) {
print("Services interrupted.", showMsgs);
}
// Leave this spot
currSegment.setIsOccupied(false);
currSegment.setTrainInside(null);
// If ready, then proceed
proceed();
// Then tell others we're done occupying that spot
currSegmentMonitor.notify();
}
}
}
继续()实施
// Move forward
private void proceed() {
// We've just moved to the next segment
currSegment = nextSegment;
nextSegment = currSegment.getNextSegment();
}
在列车进入系统之前,它必须等待进入段清除。入口段由第一站(S1)之前的>
字符表示。
进入循环后,某个段的任何列车必须等待,以便下一个段在进行之前清除。这是通过wait()
当前段实现的,直到另一个列车线程notify()
为止。
然而,经过测试,wait()
并未尊重notify()
s ,导致列车无缘无故等待,系统陷入僵局
我用两个或更多线程测试系统。
其他观察
我尝试使用try
替换wait()
块,代码为:
while (nextSegment.isOccupied());
我认为删除wait()
会有效,但由于某种原因它仍然会导致死锁。
但有趣的是,在忙等待中放置调试打印语句时,如下所示:
while (nextSegment.isOccupied()) {
System.out.println("Next segment: " + nextSegment.isOccupied());
}
它正常工作。
答案 0 :(得分:2)
不要使用显示器。监视器的问题是如果没有线程在等待,则忽略notify()
调用。
改为使用Semaphore
,其中"允许"代表进入细分受众群的许可,即该细分受众群是"免费"。
当列车想要输入某个细分时,它会调用acquire()
,当它离开细分时,会调用release()
。所有段都用1个许可证初始化,即所有段最初都是空的"。
您甚至可以使用availablePermits()
来确定该细分受众群目前是否已被占用"。
<强>更新强>
如果您不想使用Semaphore
,那么您的代码有什么问题:
您的代码是&#34;锁定&#34;当前段,因此访问该段是受控制的,但以下代码违反了:
while (nextSegment.isOccupied()) {
currSegmentMonitor.wait();
}
这里代码访问nextSegment
而没有锁定该段,即没有在段上同步。
除此之外,代码正在等待错误的监视器,因为它正在当前监视器上等待,即使它应该在 next 监视器上等待。
将代码更改为此,以修复它:
synchronized (nextSegment) {
while (nextSegment.isOccupied()) {
nextSegment.wait();
}
}