如何完成线程上下文切换?

时间:2010-12-31 09:42:56

标签: java multithreading operating-system

据我所知,在进程上下文切换操作系统'备份'寄存器和指令指针(也是寄存器的一部分)。

但是如果在进程内的线程之间切换,操作系统会备份完整的寄存器内存和堆栈吗?

我问这个的原因是要了解Java的 volatile 关键字在单核处理器的情况下是否有任何意义。

6 个答案:

答案 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可以被不同的线程更改,并且不应该优化对它的访问。

这是有效的行为,因为跨线程访问只能保证与

一起使用
  • 易失性和同步关键字
  • 表示为线程安全的类(例如java.util.concurrent。*)

<强>更新

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副本同步。