英文:
Do Android ART and HotSpot behave differently in non-volatile variable visibility?
问题
我在HotSpot和Android ART上测试了下面的代码片段,但结果不同。
在HotSpot上,MyThread
永远无法获取更新后的 isRunning
值,它始终为 true
...
但是当我在ART上测试时,MyThread
可以获取更新后的 isRunning
值,并正常退出循环...
根据我了解的Java happens-before规则,非volatile变量在多线程间不可见,就像下面的代码在Hotspot上的行为一样。
这是否取决于虚拟机的实现?或者Android ART是否有自己的优化?
class MyThread extends Thread {
public boolean isRunning = true;
@Override
public void run() {
System.out.println("MyThread running");
while (true) {
if (!isRunning) break;
}
System.out.println("MyThread exit");
}
}
public class RunThread{
public static void main(String[] args) {
new RunThread().runMain();
}
public void runMain() {
MyThread thread = new MyThread();
try {
thread.start();
Thread.sleep(500);
thread.isRunning = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
英文:
I tested the below piece of code on HotSpot and Android ART, but with different results.
On HotSpot, MyThread
never gets the updated isRunning
, it get isRunning
= true always...
But when I test it on ART, MyThread
can get the updated isRunning
and exit loop normally...
As I know about java happens-before rule, an non-volatile is not visible across multi-thread, just like the behave of the code below on Hotspot.
Does it depends on VM implementation? Or maybe Android ART has their own optimization?
class MyThread extends Thread {
public boolean isRunning = true;
@Override
public void run() {
System.out.println("MyThread running");
while (true) {
if (isRunning == false) break;
}
System.out.println("MyThread exit");
}
}
public class RunThread{
public static void main(String[] args) {
new RunThread().runMain();
}
public void runMain() {
MyThread thread = new MyThread();
try {
thread.start();
Thread.sleep(500);
thread.isRunning = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
</details>
# 答案1
**得分**: 0
> 一个非易失性变量在多线程之间不可见,就像下面代码在Hotspot上的行为一样。
这并不是_完全_正确的。在没有任何附加同步或其他先于关系的情况下,非易失性写操作并不_保证_对另一个线程中相同变量的读操作可见。但它是_允许_可见的。我曾经在没有任何先于关系的情况下,看到过HotSpot使得跨线程的写操作变得可见。基于我对此的经验,我怀疑如果你在代码中移除那个`Thread.sleep`调用,HotSpot也会使得对`isRunning`的写操作对线程可见,尽管写操作与读操作之间没有任何先于关系。
你绝对是对的,这是与虚拟机相关的,甚至可能/很有可能是与处理器架构相关的,因为不同的架构可以免费提供不同数量的同步,或者具有影响内存地址是从核心缓存中读取还是从主内存中获取的不同数量的缓存。
总之,你绝不能依赖这种行为在任何特定虚拟机上以任何特定方式工作——它有可能会在没有警告的情况下发生变化。
<details>
<summary>英文:</summary>
> an non-volatile is not visible across multi-thread, just like the behave of the code below on Hotspot.
That's not _quite_ right. A non-volatile write, absent any additional synchronization or other happens-before relationship, is not _guaranteed_ to be visible to a read of that same variable in another thread. It's _allowed_ to be visible, though. I've absolutely seen HotSpot make writes visible across threads despite no happens-before relationship. Based on my experience with this, I suspect that if you remove that `Thread.sleep` call in your code, HotSpot will also make the write to `isRunning` visible to the thread, despite the lack of any happens-before relationship between the write and the read.
You're definitely right that it's VM-specific, and it's possibly/likely even processor architecture–specific, since different architectures may give different amounts of synchronization for "free", or have different amounts of cache that affect whether a memory address is read from a core's cache or fetched from main memory.
In summary, you should never rely on this sort of behavior working any specific way on any specific VM—it's liable to change without warning.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论