C# 多线程安全问题

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Task_safe
{
    class Program
    {
        static void Main(string[] args)
        {
            Task_safe1();
            Task_safe2();
            Console.ReadKey();
        }
        public static void Task_safe1()
        {
            for (int i = 0; i <= 2; i++)
            {
                Task.Run(() =>
                {
                Console.WriteLine($"Task_safe1当前i的值为{i}");
                });
            }
        }
        public static void Task_safe2()
        {
            List<int> lt = new List<int>();
            for (int i = 0; i <= 10000; i++)
            {
                Task.Run(() =>
                {
                    lt.Add(i);
                });
            }
            Thread.Sleep(5000);
            Console.WriteLine(lt.Count.ToString());
        }
    }
}

 

问题1:Task_safe1()中当循环走完0,1,2时Task.Run()实际上还没启动,所以其实Task.Run()真正启动是i已经等于2了,所以打印结果一直为Task_safe1当前i的值为2。

问题2:由于For循环中数据量多,需启动10000线程,这10000个线程有可能其中有几个线程在同一时刻同时执行,因此会出现数据顶掉的情况。所以计数的值会小于10000。

结果:

 

解决方案

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Task_safe
{
    class Program
    {
        static void Main(string[] args)
        {
            Task_safe1();
            Task_safe2();
            Console.ReadKey();
        }
        public static void Task_safe1()
        {
            for (int i = 0; i <= 2; i++)
            {
                int k = i;//添加后就可以
                Task.Run(() =>
                {
                Console.WriteLine($"Task_safe1当前i的值为{k}");
                });
            }
        }
        private static readonly object obj = new object();//创建object变量
        public static void Task_safe2()
        {
            List<int> lt = new List<int>();
            for (int i = 0; i <10000; i++)
            {
                    Task.Run(() =>
                    {
                        lock(obj)//加锁,只有一个线程能进入执行,从而不会出现多个线程同一时间同时进来
                        {
                            lt.Add(i);
                        }
                    });
            }
            Thread.Sleep(5000);
            Console.WriteLine(lt.Count.ToString());
        }
    }
}

 

 

 结果:

 

 

posted on 2021-10-25 10:11  云里无痕  阅读(223)  评论(0)    收藏  举报