线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步

线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步

 2014/9/23 15:57:25  Darren Ji  程序员俱乐部  我要评论(0)
  • 摘要:假设多个线程共享一个静态变量,如果让每个线程都执行相同的方法每次让静态变量自增1,这样的做法线程安全吗?能保证自增变量数据同步吗?本篇体验使用lock语句块和Interlocked类型方法保证自增变量的数据同步。□线程不安全、数据不同步的做法classProgram{staticintsum=0;staticvoidMain(string[]args){Stopwatchwatch=newStopwatch();watch.Start();Parallel.For(0,Environment
  • 标签:方法 使用 数据 线程 同步

假设多个线程共享一个静态变量,如果让每个线程都执行相同的方法每次让静态变量自增1,这样的做法线程安全吗?能保证自增变量数据同步吗?本篇体验使用lock语句块和Interlocked类型方法保证自增变量的数据同步。

 

□ 线程不安全、数据不同步的做法

 

monospace; width: 100%; margin: 0em; background-color: #f0f0f0">    class Program
    {
        static int sum = 0;
        static void Main(string[] args)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            Parallel.For(0, Environment.ProcessorCount, i =>
            {
                for (int j = 0; j < 100000000; ++j)
                {
                    AddOne();
                }
            });
            watch.Stop();
            Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
            Console.ReadKey();
        }
        static void AddOne()
        {
            sum++;
        }
    }

○ 变量sum是静态的,供所有线程共享
○ Parallel.For提供并行循环, Environment.ProcessorCount表示处理器的处理,如果有4个CPU,就做4组循环

33

我们发现,结果不是我们期望的400000000,也就是说,在这种情况下的静态变量自增不是线程安全的,换句话说,无法保证共享数据的同步。

 

□ 通过lock语句块保持数据同步

 

lock语句块能保证在同一时间只有一个线程进入其中。
    class Program
    {
        static int sum = 0;
        private static readonly object o = new object();
        static void Main(string[] args)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            Parallel.For(0, Environment.ProcessorCount, i =>
            {
                for (int j = 0; j < 100000000; ++j)
                {
                    AddOne();
                }
            });
            watch.Stop();
            Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
            Console.ReadKey();
        }
        static void AddOne()
        {
            lock (o)
            {
                sum++;
            }
            
        }
    }

34

这一次,使用lock语句块得到了预期的结果。

 

□ 使用Interlocked保持数据同步

对于int或long类型变量的自增,并且保证类型安全,可以使用Interlocked类。提供的方法包括:

 

○ int Interlocked.Increment(ref int location),自增1
○ long Interlocked.Increment(ref long location),自增1
○ int Interlocked.Decrement(ref int location),自减1
○ long Interlocked.Decrement(ref long location),自减1
○ int Interlocked.Add(ref int location, int value),自增一个值
○ long Interlocked.Add(ref long location, long value),自增一个值

 

    class Program
    {
        static int sum = 0;
        static void Main(string[] args)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            Parallel.For(0, Environment.ProcessorCount, i =>
            {
                for (int j = 0; j < 100000000; ++j)
                {
                    AddOne();
                }
            });
            watch.Stop();
            Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
            Console.ReadKey();
        }
        static void AddOne()
        {
            Interlocked.Increment(ref sum);
        }
    }

35
使用Interlocked也能保证线程安全、数据同步,但耗时较长。


总结:
○ lock语句块和Interlocked类型方法都能保证自增变量的线程安全、数据同步
○ Interlocked类型方法只适用于int,long类型变量,有一定的局限性

 

线程系列包括:

线程系列01,前台线程,后台线程,线程同步

线程系列02,多个线程同时处理一个耗时较长的任务以节省时间

线程系列03,多线程共享数据,多线程不共享数据

线程系列04,传递数据给线程,线程命名,线程异常处理,线程池

线程系列05,手动结束线程

线程系列06,通过CLR代码查看线程池及其线程

线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步

发表评论
用户名: 匿名