线程安全和中间量 Lock
{
List<int> intlist = new List<int>();
for (int i = 0; i < 10000; i++)
{
intlist.Add(i);
}
}//正常for循环完毕是 i=9999
{
List<int> intlist = new List<int>();
List<Task> tasklist = new List<Task>();
int k = 0;
for (int i = 0; i < 10000; i++)
{
Task.Run(() =>
{
lock (obj_Lock)
{
intlist.Add(i);
}
});
}
Task.WaitAll(tasklist.ToArray());
} //多线程循环完 k肯定是小于10000的
线程安全:一段业务逻辑,单线程执行和多线程执行后的结果如果完全一致,是线程安全的;否则就表示是线程不安全;
1.锁,加索--直接是标准锁-- - 锁的本质,是独占引用;加锁以后;反多线程-- - 不再是多线程执行了 - 可以解决线程安全问题-- - 不推荐大家使用--加锁--影响性能
a) 标准写法:
private readonly static object obj_Lock = new object();
lock (obj_Lock) { intlist.Add(i); }
b) 锁对象--不要去锁String 锁 This
2.直接使用单线程?(分块/分区去执行,每一个区块对应一个线程) 把要操作的整块数据,做一个切分:例如有1000条数据,可以把这一万条数据分区、分块;分三块;每一块开启一个线程去执行;三个线程
每一个线程内部执行的动作是单线程--线程安全等待三个线程执行结束以后,再单线程做一个统一汇总;需要把程序加以设计才能完成;
//分块、分区执行解决线程安全问题
{
List<int> intlist1 = new List<int>();
List<int> intlist2 = new List<int>();
List<int> intlist3 = new List<int>();
int length = 10000;
int Num1 = 3000;
int Num2 = 6000;
int Num3 = 10000;
List<Task> taskList = new List<Task>();
taskList.Add(Task.Run(() =>
{
for (int i = 0; i < Num1; i++)
{
intlist1.Add(i);
}
}));
taskList.Add(Task.Run(() =>
{
for (int i = Num1; i < Num2; i++)
{
intlist2.Add(i);
}
}));
taskList.Add(Task.Run(() =>
{
for (int i = Num2; i < Num3; i++)
{
intlist3.Add(i);
}
}));
Task.WaitAll(taskList.ToArray());
intlist1.AddRange(intlist2);
intlist1.AddRange(intlist3);
}
}
3.使用线程安全对象 看看数据结构 线程安全对象 List/Arraylist 都不是线程安全的集合--把list Arraylist 换成安全对象;
BlockingCollection<int> blockinglist = new BlockingCollection<int>();
ConcurrentBag<int> conocurrentbag = new ConcurrentBag<int>();
ConcurrentDictionary<string, int> concurrentDictionary = new ConcurrentDictionary<string, int>();
ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();
ConcurrentStack<int> concurrentStack = new ConcurrentStack<int>();
OrderablePartitioner<int> OrderablePartitioner = new OrderablePartitioner<int>();
Partitioner<int> partitionerArray = new Partitioner();
中间变量
{
for (int i = 0; i< 5; i++)
{
Debug.WriteLine($"ThreadID={Thread.CurrentThread.ManagedThreadId.ToString("00")}_i={i}");
}
} //每次打印的i都为5 在循环内部:如果直接变量i,当线程执行的时候:i会变成5;
Task开启线程的时候,延迟开启--(延迟时间很短的); 开启多线程执行不会阻塞主线程;在循环的时候,不会阻塞主线程,循环很快;当有一个线程在正式的执行业务逻辑的时候;循环已经结束了;i已经变成5了
可以另外定义个变量---变量,在每次循环的时候,赋值;循环多少次,就会有多少个k,每个线程使用的是每一次循环内部的k;
在多线程中,使用这个变量的值
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
int k = 0;
tasks.Add(Task.Run(() =>
{
Debug.WriteLine($"ThreadID={Thread.CurrentThread.ManagedThreadId.ToString("00")}_i={i}__ k={ k}");
}));
}
Task.WaitAll(tasks.ToArray());
}
注意这个变量一定要在循环内部去定义,在外部定义在循环内部赋值是不解决问题的
浙公网安备 33010602011771号