线程永远不会获得共享锁

时间:2018-12-13 15:50:52

标签: java multithreading locking thread-synchronization

我正在学习老式的Java同步机制,偶然发现了一些问题。代码在GitHub上可用。

请考虑以下测试示例。

从main方法开始,我们构造一个车库Platform对象,由一个char矩阵表示。已经停放了两辆车(用 x 表示)和一辆站在路旁的车辆(用 v 表示)。汽车从位置(1,0)进入车库,并通过红色行驶,左右移动以寻找可用的停车位。

enter image description here

在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从来没有得到处理器时间,所有的汽车都停滞了。

enter image description here

我在这里想念什么?

更新:

由于yield()没有释放锁,所以我尝试使用wait()-并获得IllegalMonitorStateException,即使wait()位于同一块同步的块中锁!

我尝试将Observer更改为TimerTask,每5秒由Timer安排一次。输出比那快得多,并且程序不会终止。

0 个答案:

没有答案