Связь между потоками и операторами println()
Я пытался создать несколько сценариев, чтобы продемонстрировать проблемы видимости при совместном использовании переменных между потоками. И я заметил, что почти во всех случаях, которые я тестировал, если внутри run() я добавил оператор System.out.println() в тот же блок кода, где я использую переменную общего доступа, проблема видимости не может быть решена. Я приведу один пример:
Подробности конфигурации - Oracle Java6 64bit, Eclipse Juno SR 2
1) С ВОПРОСОМ ВИДИМОСТИ:
public class NoVisibility_Demonstration extends Thread { boolean keepRunning = true; public static void main(String[] args) throws InterruptedException { NoVisibility_Demonstration t = new NoVisibility_Demonstration(); t.start(); Thread.sleep(1000); t.keepRunning = false; System.out.println("keepRunning is false"); } public void run() { int x = 1; while (keepRunning) { //System.out.println("If you uncomment this line, the code will work without the visibility issue"); x++; } System.out.println("x:"+x); }
}
ВЫХОД: поток продолжает работать бесконечно
- 2) БЕЗ ВОПРОСА О ВИДИМОСТИ:
ОДИН ЖЕ КОД, КАК ВЫШЕ, С НЕОПРЕДЕЛЕННЫМ ЗАЯВЛЕНИЕМ println () В РАБОТЕ ()
ВЫХОД:
...
Если вы раскомментируете эту строку, код будет работать без проблем с видимостью
Если вы раскомментируете эту строку, код будет работать без проблем с видимостью
Если вы раскомментируете эту строку, код будет работать без проблем с видимостью
х: 19391
keepRunning - это ложь
Поскольку я заметил подобное поведение во всех примерах, которые я пробовал, мне интересно, есть ли какая-либо проверка целостности данных JVM перед любой операцией ввода-вывода.
2 ответа
PrintWriter синхронизируется
public void println(String x) {
synchronized(this) {
this.print(x);
this.newLine();
}
}
Два последовательных вызова System.out.println()
в главном потоке и во втором потоке создайте порядок синхронизации между двумя потоками. Это означает, что все действия (в вашем случае это обновление переменной), которые произошли в главном потоке перед освобождением монитора (выход из синхронизированного метода), будут видны кодом, выполненным во втором потоке после того, как он получит монитор (введите синхронизированный метод),
Проще говоря, да, звонит System.out.println()
делает эту синхронизацию.
Это поведение зависит от реализации. В OpenJDK, println
Тело синхронизировано, хотя API не утверждает, что это так.