java - 是否可以修改一个非 volatile 变量,使另一个线程能够 "see"更新?

标签 java synchronization

我有一个 Thread-X,它每秒读取一个非 volatile 变量,这样做没有任何同步方法。

现在我想知道是否有某种方法可以修改 Thread-Y 上的非 volatile 变量,以便 Thread-Y 的写入(最终)在 Thread-X 上可见?

public class Test {
    private static boolean double = 1; // this variable is
                                             // strictly not volatile

    public static void main(String args[]) {
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(variable);
                    try {
                        java.lang.Thread.currentThread().sleep(1000);
                    } catch (java.lang.InterruptedException e) {
                    }
                }
            }
        }).start(); // line 17
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                // the task is to change variable to "2" such the write
                // is (eventually) registered by the other threads

                // allowed to use any synchronization/locking techniques
                // required, but line 1 to line 17 must not be changed
            }
        }).start();
    }
}

是否可以修改一个非 volatile 变量,以便另一个在没有任何同步技术(原始读取)的情况下读取它的线程能够最终“看到”更新?

背景:

我需要从大量线程读取一个变量,无限 次。

据我了解(如果我错了请纠正我),在大多数 CPU(例如 x86)上,volatile 变量的读取“几乎完全免费”但不是“完全免费”。

现在,由于我从无限 数量的线程中读取了无限 数量的数据,我希望该变量是非 volatile .然而,一旦发生在蓝色月亮上,变量就需要更新。在我的用例中,更新该变量花费多少成本并不重要,但该更新最终必须可以被读取器线程读取。

解决方案:

基于 Tomasz's comment ,我已经构建了这个解决方案,我想知道 Solution-1 是有缺陷还是可靠?

public class Solution1 {
    private static double variable = 1; // this variable is
                                        // strictly not volatile

    public static void main(String args[]) {
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(variable);
                    try {
                        java.lang.Thread.currentThread().sleep(1000);
                    } catch (java.lang.InterruptedException e) {
                    }
                }
            }
        }).start(); // line 17
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                variable = 2;
                // writer-thread now terminates,
                // is it guaranteed that when it
                // "terminates successfully", variable
                // is updated on the reader-thread ?
            }
        }).start();
    }
}

基于 Joonas's comment ,我已经构建了这个解决方案,我想知道 Solution-2 是有缺陷还是可靠?

public class Solution2 {
    private static double variable = 1; // this variable is
                                        // strictly not volatile
    private static volatile boolean lock = false;

    public static void main(String args[]) {
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(variable);
                    try {
                        java.lang.Thread.currentThread().sleep(1000);
                    } catch (java.lang.InterruptedException e) {
                    }
                }
            }
        }).start(); // line 17
        new java.lang.Thread(new java.lang.Runnable() {

            @Override
            public void run() {
                variable = 2;
                lock = false; // does this line guarantee
                                // that other threads will now 
                                // see the update to variable (piggypacking)?

                // now let's assume this thread doesn't terminate
            }
        }).start();
    }
}

最佳答案

Is it possible to modify a non-volatile variable such that another thread which reads it without any synchronization techniques (raw read) is able to "see" the update eventually?

不可以。必须使用一些同步技术,否则 (JIT) 编译器可以将您的行优化为 System.out.println(false); (如果 false 是该线程首先看到的值)。也就是说,它可以优化读取变量。

我不知道实际这样做的可能性有多大,但根据 Java 内存模型,这是可以的,因此您的选择是:

  • volatile 。对于您的情况,这可能是最简单、最轻便的选择。
  • AtomicBoolean。关于它与 volatile 的一些讨论 herehere .
  • 同步 block 。在这种情况下有点矫枉过正。
  • java.util.concurrent.locks.Lock。比 synchronized 中的功能更多。
  • Thread.join()。在这种情况下没有用(读取线程将等待编写器终止)。
  • Piggybacking.想都别想。太多的事情可能会出错。

只需使用 volatile 并让 JVM 担心如何高效地实现它。 It's not expensive.

关于java - 是否可以修改一个非 volatile 变量,使另一个线程能够 "see"更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9580605/

相关文章:

java - 无法正确访问共享首选项数据

SQL Server 2005 - 同步开发/生产数据库

java - 我如何使用 html 在 JTextPane 中使用 tabulator\whitespace?

java - 如何停止为 Java 中的不同类创建相同的方法

java - 使用 Java 将客户端连接到本地主机时出现问题

java - 将 2 方法与另一个方法同步,但彼此之间不同步

c# - 如何在调用重方法之前使标签可见

java - python中的正则表达式不匹配单词

java - 为什么我不能直接访问(并锁定)对象用于同步块(synchronized block)的隐式锁

javascript - 如何在 JavaScript 中同步 API 响应?