c#和java的volatile关键字的行为方式是否相同?

时间:2013-05-01 20:06:43

标签: c# java multithreading volatile

我知道在java中,如果有多个线程访问未标记为volatile的变量,则可能会出现一些意外行为。

示例:

private boolean bExit;

 while(!bExit) {
    checkUserPosition();
    updateUserPosition();
 }

如果您将bExit变量标记为有毛病,那么可以保证其他线程会看到最近的值。

c#的行为方式是否相同?

更新

例如,在C#中执行此操作:

int counter = ...;

for(...)
{
   new Thread(delegate()
   {

      Interlocked.Decrement(ref counter);
   }
}


if(counter == 0) 
{
   // halt program
}

在上文中,在c#中,您是否必须将计数器变量标记为volatile或者这将按预期工作?

2 个答案:

答案 0 :(得分:0)

  

如果你将bExit变量标记为voilatile,那就会保证这一点   其他线程将看到最新的值。 c#的行为方式是否相同?


是的,但都取决于您访问共享变量的方式。例如,如果以Interlocked.Decrement之类的线程安全方式访问variyable,即使不使用voilatile也不会出现问题。

volatile (C# Reference from MSDN)

  

volatile关键字表示字段可能被修改   多个线程同时执行。是的领域   声明的volatile不受编译器优化的限制   假设由单个线程访问。 这确保了最多   字段中始终存在最新值

What is the "volatile" keyword used for?

答案 1 :(得分:0)

您需要在这里做一点小心,因为您在示例中选择了两种不同的类型。我的一般经验法则是,volatile最好用于布尔值,而其他一切你可能需要其他类型的同步机制。在C#和java中非常常见的是使用volatile布尔值来例如停止一个循环或任务执行,它具有来自多个线程的可见性:

class Processor
{
    private volatile Boolean _stopProcessing = false;

    public void process()
    {
        do
        { ... }
        while (!_stopProcessing);
    }

    public void cancel()
    {
        _stopProcessing = true;
    }
}

以上内容适用于C#或java,在此示例中,volatile关键字表示process方法中的读取将来自实际当前值,而不是缓存值。编译器或VM可以选择以其他方式允许缓存该值,因为进程中的循环不会更改_stopProcessing本身。

所以第一个问题答案是肯定的。

虽然你可以在int上使用volatile,但这只有在你只阅读或写一个值时才有帮助。一旦你做了更复杂的事情,例如递增,您需要一些其他类型的同步,例如您使用Interlocked。在您的第二个示例中,您仍然在阅读计数器的值而没有任何同步,因此您有效地依赖于计数器的其他用法进行同步(例如,使用Interlocked)。

在你的第二个例子中,你最好将你的int标记为易失性,这样你再次可以确定你获得的是当前值而不是某些缓存版本。但是单独使用volatile是不够的,因为底部的读取可能与标准的减量(counter--)重叠,而不是正确使用Interlocked。