据我所知,在进程上下文切换操作系统'备份'寄存器和指令指针(也是寄存器的一部分)。
但是如果在进程内的线程之间切换,操作系统会备份完整的寄存器内存和堆栈吗?
我问这个的原因是要了解Java的 volatile 关键字在单核处理器的情况下是否有任何意义。
答案 0 :(得分:7)
如果Java的volatile关键字在单核处理器的情况下具有任何重要性。
jit编译器使用的优化可能会导致意外行为。
static boolean foo = true;
public void bar(){
while(foo){
//doSomething
//do not modify foo in here
}
}
这可能是优化的,因为foo在循环内没有改变。
public void bar(){
while(true){
//Now this loop never ends
//changes to foo are ignored
}
}
使foo
volatile
告诉jit编译器foo
可以被不同的线程更改,并且不应该优化对它的访问。
这是有效的行为,因为跨线程访问只能保证与
一起使用<强>更新强>
volatile关键字不会影响上下文切换本身,但它会影响变量的读写方式。这不仅会影响cpu缓存的使用(对多核系统很重要),还会影响上面刚才编译器使用的优化(在所有系统中都很重要)。
答案 1 :(得分:4)
了解Java的volatile关键字在单核处理器的情况下是否具有任何意义。
这种思路是不明智的。您应该根据API(虚拟机)的定义进行编程。你不应该依赖某些特定效果或缺乏效果的某些东西(在这种情况下,volatile
的效果)不属于其记录的定义。 即使实验表明它在特定情况下也有特殊行为。因为会咬你。
答案 2 :(得分:3)
线程切换确实意味着存储所有计算寄存器和所有堆栈,因为每个线程确实有一个单独的内存堆栈。
由于Java内存模型的工作方式,volatile
关键字在多线程中仍然很重要,即使在单核环境中也是如此。 volatile
变量不存储在任何类型的缓存或寄存器中,而是始终从主存储器中获取,以确保每个线程始终可以看到变量的最新值。
答案 3 :(得分:2)
是的,即使对于单核处理器,volatile
仍然有用。它告诉编译器每次读取时都需要从内存重新读取该值(因为另一个线程可能正在更新它),而不只是缓存在寄存器中。
答案 4 :(得分:2)
查看JSR 133,特别是标有“挥发性做什么?”
的部分易失性字段是特殊字段 用于沟通状态 线程之间。每次读取一个 volatile会看到最后一次写入 任何线程都不稳定;在 效果,它们由指定 程序员作为它的领域 永远不会接受看到“陈旧” 由缓存或 重新排序。
这是volatile
如何与JVM内存模型一起使用的有用介绍和描述。
答案 5 :(得分:0)
我知道volatile
做了什么,但我想知道为什么这是必要的。让我详细说明一下。
如上面的josefx所述。如果我们有以下内容: -
while(run) {
//do something but don't modify run
}
如果某个其他线程将run
转为false
,那么while循环将永远不会结束。正如之前由Yuval A所提到的,在线程上下文切换期间,寄存器也会被备份。所以我猜它就是这样的。
如果任何线程修改了run
的值,则该值将仅在寄存器中修改。在线程上下文切换期间,如果没有明确标记为volatile
,Java将不会将此寄存器值与RAM中的副本同步。这样每个线程都可以使用自己的run
版本。但是这个概念不适用于非基元和整数等基元,它们不能完整地放在寄存器中,迫使它们与RAM副本同步。