java - Java 中 System.out.println() 的 volatile

标签 java multithreading thread-safety system.out

我在许多帖子中读到争论 System.out.println() 使代码在某种程度上是线程安全的,因此要模拟比赛 System.out.println()应该从代码中删除。

现在 PrintStreamwrite() 方法在写入流之前在 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/

相关文章:

multithreading - 使用 Numba 对 2 个矩阵求和的最快方法是什么?

c - APUE<2nd> 11.4,先发信号或先解锁

.net - 同一事务中的并发数据库 (PostgreSQL) 命令

java - 如何从 html5 websocket 计算出负载大小

java - 转换不可修改的集合

java - 用户需要按两次回车键才能初始化循环

multithreading - Golang : How to capture return values of massively parallel benchmark (> 1 million tasks)?

c++ - 如何使用正确的内存对齐方式从堆中为 InterlockedIncrement 函数分配内存?

ruby - 是否可以确保线程代码在 Ruby 中没有副作用?

使用 2 个不同 key 的 Java Triple DES 加密