Два потока получают одинаковое значение - PullRequest
3 голосов
/ 22 апреля 2020

Я изучаю многопоточность.

Ниже приведен небольшой фрагмент кода

@NotThreadSafe
public class UnsafeSequence {

    private int value;

    public int getNext() {

        return value++;

    }
}

Я хочу знать, когда и как two different threads может получить то же value? Любой сценарий, пожалуйста, поделитесь?

Ответы [ 2 ]

3 голосов
/ 22 апреля 2020
UnsafeSequence seq = new UnsafeSequence();

new Thread(() -> System.out.println(seq.getNext())).start();
new Thread(() -> System.out.println(seq.getNext())).start();

Достаточно просто. Это имеет возможность напечатать тот же номер. Почему?

value++ переводится в value = value + 1

Скажите, что Thread 1 читает значение как 0 и добавляет к нему 1, но не присваивает его обратно value еще. В то же время Thread 1 читает значение как 0 и добавляет к нему 1. Теперь, точно так же, у нас есть состояние гонки, и 1 выводится дважды.

Вы можете решить эту проблему с помощью AtomicInteger

public class Safe {

    private AtomicInteger value;

    public int getNext() {

        return value.getAndIncrement();

    }
}

Теперь это безопасно и никогда не будет печатать одно и то же число дважды

0 голосов
/ 22 апреля 2020

value++ не является atomic operation (что означает ни одну неделимую операцию).

За value++ скрыто 3 операции (чтение-изменение-запись) ->

int temp = value;
temp = temp + 1;
value = temp;

При некоторой неудачной синхронизации 2 потока могут прочитать старое значение (int temp = value) и, таким образом, сгенерировать приращение lost update -> 2, дающее то же конечное значение.

Это называется race condition потому что результат операции зависит от планирования и чередования нескольких потоков во время выполнения.

Эта последовательность операций должна быть атомарной c, и для этого необходимо использовать некоторые механизмы синхронизации.

Пример "некоторых" решений:

A. Используйте атоми c переменные (из пакета java.util.concurrent.atomic). Лучший подход в этом примере

B. Используйте intrinsi c замок (synchronized)

@ThreadSafe
public class SafeSequence {

    private int value;

    public synchronized int getNext() {

        return value++;

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