Подтвердить что ты не робот

Как работает join()? (Многопоточность в Java)

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

Вопрос

(множественный выбор): Каковы некоторые из возможных результатов для программы ниже?

А)   Значение равно 1.   Значение равно 1.   Конечное значение равно 1.

В)   Значение равно 1.   Значение равно 1.   Конечное значение равно 2.

С)   Значение равно 1.   Конечное значение равно 1.   Значение равно 2.

D)   Значение равно 1.   Конечное значение равно 2.   Значение равно 2.

Программа

public class Thread2 extends Thread {

    static int value = 0;
    static Object mySyncObject = new Object();

    void increment() {

        int tmp = value + 1;
        value = tmp;

    }

    public void run() {

        synchronized(mySyncObject) {

            increment();
            System.out.print("Value is " + value);

        }

    }

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread2();
        Thread t2 = new Thread2();

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.print("Final value is " + value);

    }

}

Правильные ответы: A), C) и D).

В случае A) я не понимаю, как возможно, что оба потока (после увеличения кажущейся статической переменной изнутри синхронизированного блока (!)) в конечном итоге устанавливаются в 1, а конечное значение также равно 1...

Случаи C и D одинаково запутывают меня, потому что я действительно не понимаю, как возможно, что main() заканчивается перед обоими необходимыми потоками (t1 и t2). Я имею в виду, что их методы join() вызывались из основной функции, поэтому, насколько мне известно, основная функция должна ждать, пока оба t1 и t2 будут выполнены с помощью метода run() (и, таким образом, будут напечатаны их значения)...??

Было бы здорово, если бы кто-нибудь мог провести меня через это.

Заранее благодарим! васаби

4b9b3361

Ответ 1

Что-то не так с ответами или вопросом.

Ваше понимание join() верное. Сообщение "Конечное значение" не может быть напечатано до тех пор, пока оба потока не будут завершены. Вызов join() обеспечивает это.

Кроме того, метод increment() вызывается только из блока synchronized, помеченного в статическом поле. Таким образом, этот метод не может быть вызван одновременно двумя потоками. Выход "Value is" также находится в одном синхронизированном блоке. Таким образом, нет доступа к свойству value из любого места, кроме встроенного блока. Поэтому эти операции являются потокобезопасными.

Единственный возможный выход из этой программы: "Значение равно 1. Значение равно 2. Конечное значение равно 2." (На самом деле, между выходами нет промежутков или промежутков - я просто согласен с форматом ответов.)

Я не могу объяснить, почему это не соответствует ни одному из ответов, кроме того, что тот, кто написал этот вопрос, что-то испортил.

Ответ 2

Сначала я хотел бы согласиться с rlibby. Его ответ может быть доказан, написав программу в виде презентации для учителя. Если мы опустим это, посмотрите на это:

у него есть два отпечатка "Value is..." невозможно напечатать "Значение равно 1" дважды, так как приращение синхронизируется статическим объектом (это исключает A и B) порядок операторов печати нельзя прогнозировать но: если мы читаем "Конечное значение - это x", должно быть значение "Значение равно X", независимо от того, было ли оно до или после, но оно должно существовать