Поток никогда не получает общую блокировку - PullRequest
0 голосов
/ 13 декабря 2018

Я изучал механизмы синхронизации Java старой школы и столкнулся с некоторыми проблемами.Код, доступный на GitHub .

Рассмотрим следующий пример теста.

Из основного метода мы создаем объект гаража Platform, представленный матрицей символов.Есть две машины, уже припаркованные (обозначенные x ), и стоящее на пути транспортное средство (обозначенное v ).Автомобили въезжают в гараж из положения (1,0) и проезжают, как показано красным, смотря вправо и влево на доступное место для парковки.

enter image description here

Из основного метода создается тридцать транспортных средств (потоков) и вызывается метод 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, запланированный на Timer на каждые 5 секунд.Вывод был намного быстрее, и программа не завершилась.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...