Почему другой поток получает доступ к заблокированному объекту, а синхронизированный раздел еще не завершен? - PullRequest
2 голосов
/ 20 сентября 2019

Сообщение «основной поток» печатается перед сообщением «новый поток», хотя метод с сообщением «новый поток» находится в синхронизированном разделе по объекту, который включает методы print *.

    Test test = new Test();
    new Thread(() -> {
        try {
            synchronized (test) {
                Thread.sleep(5000);
                test.printMessage();
            }
        } catch (InterruptedException e) {}
    }).start();
    Thread.sleep(1000);
    test.printAnotherMessage();
}

public void printMessage() {
    System.out.println("new Thread");
}

public void printAnotherMessage() {
    System.out.println("main Thread");
}

}

Ответы [ 2 ]

3 голосов
/ 20 сентября 2019

В этом примере отсутствует синхронизация между printAnotherMessage и синхронизированным блоком, который спит в течение 5 секунд, поэтому основной поток спит в течение 1 секунды и затем печатает main Thread без ожидания.

Вы, вероятно,намеревался сделать printAnotherMessage синхронизированным методом.В этом случае основной поток будет ждать, пока другой поток завершит выполнение блока, синхронизированного с тестовым объектом.

2 голосов
/ 20 сентября 2019

Синхронизация на test.printAnotherMessage(); отсутствует, поэтому она будет выполнена сначала при условии правильного выбора времени.4 секунды - это много, и их должно быть достаточно.

synchronized (test) {
    test.printAnotherMessage();
}

Thread.sleep редко бывает хорошим вариантом.Более правильным способом было бы

Test test = new Test();

new Thread(() -> {
    synchronized (test) {
        test.printMessage();
        test.notify();
    }
}).start();

synchronized (test) {
    test.wait();
    test.printAnotherMessage();
}

Я играю в опасную игру здесь, поскольку я предполагаю, что основной поток войдет в синхронизированный блок и выполнит wait() до того, как будет создан другой поток.и он входит в свой синхронизированный блок.Это разумно, поскольку создание потока займет некоторое время .

Test test = new Test();
new Thread(() -> {
    try {
        // a lot of time to let the main thread execute wait()
        Thread.sleep(500); 

        synchronized (test) {
            test.printMessage();
            test.notify();
        }
    } catch (InterruptedException e) {}
}).start();

synchronized (test) {
    test.wait();
    test.printAnotherMessage();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...