Чего не следует делать при использовании потоков: запись и чтение одной и той же переменной без надлежащей синхронизации.Вы нарушаете это правило и поэтому сталкиваетесь с ожидаемыми проблемами с неопределенными результатами.
Представьте себе следующий поток выполнения:
T1: set var to "Hello"
T2: checks var and notices it is a String, proceeds to print it.
T1: set var to null
T2: prints var. (which is already null again)
Возможное решение состоит в том, что T2 сначала копирует значение в поток-local и затем продолжает работать над этим, iE:
while (running) {
final String localString = staticString;
if (localString != null) {
System.out.println(localString);
}
}
Таким образом, вы создаете «снимок» текущего значения переменной и фактически выводите то, что было снято в этот момент.Однако это по-прежнему недопустимый способ синхронизации между потоками, поскольку состояние моментального снимка является абсолютно случайным.Представьте, что происходит следующее:
T1: set var to "hello"
T1: set var to null
T2: checks var, it is null, do nothing.
T1: set var to "world"
T1: set var to null
T2: checks var, it is null, do nothing.
При работе с потоками необходимо помнить, что состояние любого потока в любое время всегда не определено, если вы не применяете его принудительно.
Существуют простые способы применения определенного состояния, например, iE synchronized
, что в основном означает «Переведите все это в режим ожидания, чтобы я мог выполнять свою работу», однако это довольно неэффективно, поскольку нет смысла работатьпараллельно, если вы постоянно ставите все на удержание.
Намного лучший способ приблизиться к многопоточности - это с точки зрения архитектуры, т.е. с помощью триггеров.В вашем случае поток-писатель может иметь очередь только с соответствующей информацией (строки для вывода), а поток-производитель помещает строки в эту очередь:
T2: checks queue, it is empty, do nothing.
T1: t1.put("Hello")
T2: checks queue, it contains "Hello", print that.
T2: checks queue, it is empty, do nothing.
T2: checks queue, it is empty, do nothing.
T1: t1.put("World")
T2: checks queue, it contains "World", print that.
Iрекомендуем прочитать параллельный пакет , чтобы узнать об инструментах, предлагаемых Java.Почти все проблемы могут быть легко решены с помощью них.