我在许多帖子中读到争论 System.out.println()
使代码在某种程度上是线程安全的,因此要模拟比赛 System.out.println()
应该从代码中删除。
现在 PrintStream
的 write()
方法在写入流之前在 this
上同步,所以每次 write()
被调用然后锁被持有和释放。
write()
打印流的方法
public void write(int b) {
try {
synchronized (this) { //acquires a lock
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
但这会影响种族行为吗?
假设:
boolean flag = true;
Thread 1:
System.out.println();
flag = false;
System.out.println();
Thread 2:
System.out.println();
while(flag){
System.out.println();
}
现在,如果我们看到两个线程都锁定了同一个对象,即 this
(PrintStream),现在 flag
包含在两个 sysouts< 之间
,它们正在获取和释放相同的锁,然后 flag
值将从缓存中刷新并在其他线程可以看到的内存中更新。
因此,由于模拟比赛很困难,理论上是否有可能此代码是线程安全的并且线程 2 将看到对 flag
所做的更改?
如果是,那么是否可以使用 System.out.println();
实现 volatile
的相同效果?
最佳答案
JLS 关于该主题有以下说法:监视器上的解锁发生在该监视器上的每个后续锁定之前。
( 17.4.5 )
您可以在 JLS 中阅读 happens-before 等的确切定义,但这基本上意味着在解锁锁之前线程中发生的每一次读取和写入都将被另一个线程看到获取锁(小心!如果有一个线程 3 在没有获取锁的情况下写入标志,则不需要同步)
由于在这种情况下您锁定在同一个对象上,这意味着是的,可以保证线程 2 必须看到更新后的 flag
值。
虽然我没有在文档中看到任何提及保证 PrintStream 获取锁并且使用线程安全,所以你依赖于这里的实现细节(一个不太可能永远虽然被打破了)。
关于java - Java 中 System.out.println() 的 volatile ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18547938/