我有一个 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 的一些讨论 here和 here .同步
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/