我正在学习老式的Java同步机制,偶然发现了一些问题。代码在GitHub上可用。
请考虑以下测试示例。
从main方法开始,我们构造一个车库Platform
对象,由一个char矩阵表示。已经停放了两辆车(用 x 表示)和一辆站在路旁的车辆(用 v 表示)。汽车从位置(1,0)进入车库,并通过红色行驶,左右移动以寻找可用的停车位。
在main方法中,创建了三十个载具(线程),并调用了start()
方法。如果前面有汽车挡住他们的路,他们必须在共享的wait()
对象上调用Platform.lock
。
Observer
类负责将车库的当前状态打印到控制台。
发生问题的地方是MysteryVehicle
线程,其唯一的工作就是清除障碍物(用 v 表示)并让汽车有序通过。看来该对象永远不会获得锁的监视器。
主班
package garage;
import garage.model.*;
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
Platform platform = new Platform();
Vehicle.platform = platform;
platform.print();
Vehicle[] vehicles = new Vehicle[30];
for (int i = 0; i < 30; i++) {
vehicles[i] = new Vehicle();
}
for (int i = 0; i < 30; i++) {
vehicles[i].start();
}
Observer observer = new Observer();
observer.platform = platform;
observer.setDaemon(true);
observer.start();
MysteryVehicle mysteryVehicle = new MysteryVehicle();
mysteryVehicle.start();
try {
mysteryVehicle.join();
} catch (Exception exception) {
exception.printStackTrace();
}
try {
for (int i = 0; i < 30; i++)
vehicles[i].join();
} catch (Exception exception) {
exception.printStackTrace();
}
platform.print();
System.out.println("END");
System.out.println(platform.flag); // checks whether wait() was called anytime
}
public static void main(String[] args) {
launch(args);
}
}
平台类
package garage.model;
public class Platform {
public boolean flag = false; // indicades whether wait() was called anytime
public char[][] fields = new char[10][8];
public static final Object lock = new Object();
public Platform() {
for (int i = 0; i < 10; i++)
for (int j = 0; j < 8; j++)
fields[i][j] = '.';
fields[1][0] = fields[2][0] = 'x'; // already parked cars
fields[4][1] = 'v'; // obstacle
}
public void print() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(fields[i][j]);
}
System.out.println();
}
System.out.println();
}
}
}
车辆类别
package garage.model;
public class Vehicle extends Thread {
int x = 1;
int y = 0;
private int block = 1;
public static Platform platform;
public boolean moving = true;
public void run() {
y++; // entrance
while (moving) {
if (block == 1) {
while (moving && platform.fields[x + 1][y] == 'v')
try {
synchronized (Platform.lock) {
Platform.lock.wait();
platform.flag = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Platform.lock) {
x++;
Platform.lock.notifyAll();
yield(); // suggest another vehicle should get processor time
}
// looking left and right for an available spot
if (platform.fields[x][0] != 'x' && platform.fields[x][0] != '*') {
platform.fields[x][0] = '*'; // park
moving = false;
} else if (x < 8 && platform.fields[x][3] != 'x' && platform.fields[x][3] != '*'
&& platform.fields[x][2] != 'v') {
platform.fields[x][3] = '*';// park
moving = false;
}
// checking if we reached the end
if (moving && x == 9) {
block = 2;
move(); // transfer to the second block of the garage
}
} // end block 1
if (block == 2) {
// looking left and right for an available spot
if (platform.fields[x][7] != 'x' && platform.fields[x][7] != '*') {
platform.fields[x][7] = '*'; // park
moving = false;
} else if (x < 8 && platform.fields[x][4] != 'x' && platform.fields[x][4] != '*'
&& platform.fields[x][5] != 'v') {
platform.fields[x][4] = '*'; // park
moving = false;
}
while (moving && platform.fields[x - 1][y] == 'v')
try {
synchronized (Platform.lock) {
Platform.lock.wait(); // waiting for the mystery vehicle to disappear
platform.flag = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (moving) {
synchronized (Platform.lock) {
x--;
Platform.lock.notifyAll();
yield();
}
}
if (x == 1) {
y++;
moving = false;
}
} // end block 2
} // end moving
}
private void move() {
while (y != 6) {
if (y + 1 == 'v')
try {
synchronized (Platform.lock) {
platform.flag = true;
Platform.lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Platform.lock) {
y++;
Platform.lock.notifyAll();
yield();
}
}
}
}
观察者类
package garage.model;
public class Observer extends Thread {
public Platform platform;
{
setPriority(MIN_PRIORITY);
}
@Override
public void run() {
while (true) {
synchronized (Platform.lock) {
try {
sleep(2000);
platform.print();
yield();
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
Platform.lock.notifyAll();
}
}
}
}
}
MysteryVehicle类
package garage.model;
public class MysteryVehicle extends Vehicle {
{
setPriority(MAX_PRIORITY);
}
@Override
public void run() {
synchronized (Platform.lock) {
System.out.println("And the vehicle disappears!");
platform.fields[4][1] = '.';
}
}
}
过一会儿,Observer
产生以下输出,该输出不会改变。看来MysteryVehicle从来没有得到处理器时间,所有的汽车都停滞了。
我在这里想念什么?
更新:
由于yield()
没有释放锁,所以我尝试使用wait()
-并获得IllegalMonitorStateException
,即使wait()
位于同一块同步的块中锁!
我尝试将Observer
更改为TimerTask
,每5秒由Timer
安排一次。输出比那快得多,并且程序不会终止。