如果一个方法在不同的线程上执行但非并发,它是否需要是 volatile?

问题描述

using System;
using System.Threading;

class Program
{
    private static int i = 0;
    private static volatile int j = 0;

    static void Main(string[] args)
    {
        Timer timer = new Timer(TimeCallback,null,1000,60 * 1000);


        Console.ReadLine();
    }

    private static void TimeCallback(object state)
    {
        i++;
        if (i > 10000 * 10000)
        {
            i = 0;
        }

        j++;
        if (j > 10000 * 10000)
        {
            j = 0;
        }


        Console.WriteLine(i + "," + j);
    }
}

在上面的代码中,TimeCallback 运行得非常快,它不能在计时器的时间间隔内并发运行。所以我知道它是原子的,不需要lock()

我的问题是,i 可以是非易失性的,还是必须像 j 一样是易失性的。

如果 i 必须是 volatile,那么 akka actor 字段怎么可以是非 volatile 的?

Should my Akka actors' properties be marked @volatile?

解决方法

如果只有一个线程,而不是主线程,使用了一些变量,并且我们确信它永远不会被另一个线程使用,就像单线程一样,所以我们不需要处理并发和同步(锁定,易失性,监控...).

我们唯一可以而且应该做的就是确保我们将代码分开并使用良好的命名以及专用的类。

例如:

class Program
{
  static void Main(string[] args)
  {
    Timer timer = new Timer(MyIsolatedThreadedProcessing.DoProcess,null,1000,60 * 1000);
    Console.ReadLine();
  }
}

static public class MyIsolatedThreadedProcessing
{
  static private int Value1 = 0;
  static private int Value2 = 0;
  static public void DoProcess(object state)
  {
    Value1++;
    if ( Value1 > 10000 * 10000 )
    {
      Value1 = 0;
    }
    Value2++;
    if ( Value2 > 10000 * 10000 )
    {
      Value2 = 0;
    }
    Console.WriteLine(Value1 + "," + Value2);
  }
}

但是线程之间使用和共享的任何东西都需要根据需要进行管理,即使是一般的读数。

所以如果多个线程可以同时调用定时器回调,那么你确实需要管理并发和同步,因为它是多线程的。

您写道“它不能在定时器的间隔内并发运行”和“定时器回调在线程池上执行,它可能运行在不同的线程上”:因此,永远不要假设“TimeCallback 运行速度非常快”之类的东西

因此,您应该以干净,坚固和标准的方式做事。因此,您将避免基本问题和偶尔的随机崩溃或冻结。

Threading in C#