is {name} 开始 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
Thread.Sleep(new Random().Next(50, 100));
if (name.Equals("btnThreadCore_Click_11"))
{
throw new Exception("btnThreadCore_Click_11异常");
}
else if (name.Equals("btnThreadCore_Click_12"))
{
throw new Exception("btnThreadCore_Click_12异常");
}
else if (name.Equals("btnThreadCore_Click_13"))
{
cts.Cancel();
}
if (!cts.IsCancellationRequested)
{
Console.WriteLine($"This is {name}成功结束 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
}
else
{
Console.WriteLine($"This is {name}中途停止 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
return;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
cts.Cancel();
}
}, cts.Token));
}
//1 准备cts 2 try-catch-cancel 3 Action要随时判断IsCancellationRequested
//尽快停止,肯定有延迟,在判断环节才会结束
Task.WaitAll(taskList.ToArray());
//如果线程还没启动,能不能就别启动了?
//1 启动线程传递Token 2 异常抓取
//在Cancel时还没有启动的任务,就不启动了;也是抛异常,cts.Token.ThrowIfCancellationRequested
}
catch (AggregateException aex)
{
foreach (var exception in aex.InnerExceptions)
{
Console.WriteLine(exception.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
View Code
临时变量:
for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
Console.WriteLine($"This is btnThreadCore_Click_{i} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});
}
为什么运行结果后,都是5呢?
临时变量问题,线程是非阻塞的,延迟启动的;线程执行的时候,i已经是5了
那么该如何解决呢?
每次都声明一个变量k去接收,k是闭包里面的变量,每次循环都有一个独立的k,5个k变量 1个i变量
for (int i = 0; i < 5; i++)
{
int k = i;
Task.Run(() =>
{
Console.WriteLine($"This is btnThreadCore_Click_{i}_{k} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});
}
这样再运行,结果就正常了。
线程安全&lock:
线程安全:如果你的代码在进程中有多个线程同时运行这一段,如果每次运行的结果都跟单线程运行时的结果一致,那么就是线程安全的
线程安全问题一般都是有全局变量/共享变量/静态变量/硬盘文件/数据库的值,只要多线程都能访问和修改
发生是因为多个线程相同操作,出现了覆盖,怎么解决?
1 Lock解决多线程冲突
Lock是语法糖,Monitor.Enter,占据一个引用,别的线程就只能等着
推荐锁是private static readonly object,
A不能是Null,可以编译不能运行;
B 不推荐lock(this),外面如果也要用实例,就冲突了
//Test test = new Test();
//Task.Delay(1000).ContinueWith(t =>
//{
// lock (test)
// {
// Console.WriteLine("*********Start**********");
// Thread.Sleep(5000);
// Console.WriteLine("*********End**********");
// }
//});
//test.DoTest();
//C 不应该是string; string在内存分配上是重用的,会冲突
//D Lock里面的代码不要太多,这里是单线程的
Test test = new Test();
string student = "水煮鱼";
Task.Delay(1000).ContinueWith(t =>
{
lock (student)
{
Console.WriteLine("*********Start**********");
Thread.Sleep(5000);
Console.WriteLine("*********End**********");
}
});
test.DoTestString();
//2 线程安全集合
//System.Collections.Concurrent.ConcurrentQueue<int>
//3 数据分拆,避免多线程操作同一个数据;又安全又高效
for (int i = 0; i < 10000; i++)
{
this.iNumSync++;
}
for (int i = 0; i < 10000; i++)
{
Task.Run(() =>
{
lock (Form_Lock)//任意时刻只有一个线程能进入方法块儿,这不就变成了单线程
{
|