一. 线程的异常处理:

 try
{
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>(); //线程里面的异常是被吞掉了,因为已经脱离try catch的范围了 如果真想让线程之外的Catch抓到异常, 那么只有使用 WaitAll 抓到多线程里面全部的异常
//实际开发: 线程里面的action不允许出现异常,自己使用try catch处理好
for (int i = 0; i < 20; i++)
{
string name = string.Format($"btnThreadCore_Click_{i}");
Action<object> act = t =>
{
try
{
Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click_11"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
if (t.ToString().Equals("btnThreadCore_Click_12"))
{
throw new Exception(string.Format($"{t} 执行失败"));
}
Console.WriteLine("{0} 执行成功", t);
}
catch (Exception ex)
{
Console.WriteLine($"Exception:{ex.Message}"); //
}
};
taskList.Add(taskFactory.StartNew(act, name));
}
// Task.WaitAll(taskList.ToArray());使用 WaitAll 捕获多线程里面全部的异常; 但是也不能总是WaitAll, 并且很多业务也不能使用WaitAll来处理 }
catch (AggregateException aex) //专门处理多线程的异常, 里面的异常有多项
{
foreach (var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

 

二. 线程的取消,

a)   场景: 多个线程并发,某个失败后,希望通知别的线程,都停下来, 尽量使用CancellationTokenSource, 不要自己创建bool变量

 try
{
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>(); //多个线程并发,某个失败后,希望通知别的线程,都停下来
//task是外部无法中止(中间停止),Thread.Abort不靠谱,因为线程是OS的资源,无法掌控啥时候取消
//线程的停止: 线程自己停止自己--公共的访问变量--修改它---线程不断的检测它(延迟少不了)
//CancellationTokenSource去标志任务是否取消 Cancel取消 IsCancellationRequested 是否已经取消了
//Token 启动Task的时候传入,那么如果Cancel了,这个任务会放弃启动,抛出一个异常
// 当一个线程不执行, 后面的线程全部都不能再执行了
CancellationTokenSource cts = new CancellationTokenSource();//bool值 //bool flag = true; 线程安全的
for (int i = 0; i < 40; i++)
{
string name = string.Format("btnThreadCore_Click{0}", i);
Action<object> act = t =>
{
try
{
//if (cts.IsCancellationRequested)
//{
// Console.WriteLine("{0} 取消一个任务的执行", t);
//}
Thread.Sleep(2000);
if (t.ToString().Equals("btnThreadCore_Click11"))
{
throw new Exception(string.Format("{0} 执行失败", t));
}
if (t.ToString().Equals("btnThreadCore_Click12"))
{
throw new Exception(string.Format("{0} 执行失败", t));
}
if (cts.IsCancellationRequested)//启动40个线程, 每一个线程都检查这个信号量, 是否改任务已经被取消
{
Console.WriteLine("{0} 放弃执行", t);
return;
}
else
{
Console.WriteLine("{0} 执行成功", t);
}
}
catch (Exception ex)
{
cts.Cancel(); //当执行抛出异常后, (t.ToString().Equals("btnThreadCore_Click11")); 将信号量设置为false, 表示取消任务
Console.WriteLine(ex.Message);
}
};
taskList.Add(taskFactory.StartNew(act, name, cts.Token));
//如果一个线程在启动的时候标识了cts.Token, 当cts.Cancel()时, 如果这个线程还没有启动, 则会被标识为取消一个任务执行; 如果这个线程已经启动, 但是还没有执行, 那么会被放弃执行
}
Task.WaitAll(taskList.ToArray()); }
catch (AggregateException aex) //专门处理多线程的异常
{
foreach (var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

三. 多线程临时变量

for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine(i); //打印结果 5个5
});
} for (int i = 0; i < 5; i++)
{
int k = i;
Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine(k); //打印结果 4,3,1,2,0
});
} //i最后是5 全程就只有一个i 等着打印的时候,i==5
//k 全程有5个k 分别是0 1 2 3 4
//k在外面声明 全程就只有一个k 等着打印的时候,k==4
int k = 0;
for (int i = 0; i < 5; i++)
{
// int k = i;
k = i;
new Action(() =>
{
Thread.Sleep(100);
Console.WriteLine($"k={k} i={i}");
}).BeginInvoke(null, null);
}

 

四. 线程安全:

try
{
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>(); //如何判断何时加锁: 线程内部声明的变量, 由于不共享的是线程安全的; 但是在线程外部操作的资源由于共享, 则就会造成线程不安全. 比如全局变量/数据库的某个值/磁盘文件
int TotalCountIn = 0;//TotalCountIn属于线程外部变量, 会有线程安全有问题
for (int i = 0; i < 10000; i++)//i属于线程外部变量, 会有线程安全有问题
{
int newI = i;//newI 属于线程内部变量, 不会有线程安全有问题
taskList.Add(taskFactory.StartNew(() =>
{
//值类型不能lock
lock (btnThreadCore_Click_Lock)//lock后的方法块,任意时刻只有一个线程可以进入
//只能锁引用类型,占用这个引用链接 不要用string 因为享元 , 可能导致锁的是同一块内存区域
{ //这里就是单线程 this.TotalCount += 1;
TotalCountIn += 1;
this.IntList.Add(newI);
} }));
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine(this.TotalCount);
Console.WriteLine(TotalCountIn);
Console.WriteLine(this.IntList.Count());
#endregion
}
catch (AggregateException aex) //专门处理多线程的异常
{
foreach (var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

五.   关于Lock变量的写法解释:

//为什么锁的变量要这样写private static readonly object btnThreadCore_Click_Lock = new object();
//private 防止外面也去锁
//static 全场唯一
//readonly不准修改, 如果不是readonly有可能会在锁的代码里面修改它
//object表示引用, 因为lock不能锁值类型

 

 六. 为什么不推荐锁this

 

//lock (this)
//{
// //this form1的实例 每次实例化是不同的锁,同一个实例是相同的锁
// //但是这个实例别人也能访问到,别人也能锁定
// //最好不要锁this
//}

 

七. Lock到底是个什么? 

//Monitor.Enter(btnThreadCore_Click_Lock);
//lock 就是一个语法糖, 类似于monitor的写法, 也就是说可以将lock{ }块中的语句, 放到Monitor的Enter和exit中间
//Monitor.Exit(btnThreadCore_Click_Lock);
Monitor.Enter(btnThreadCore_Click_Lock);
//lock 就是一个语法糖, 类似于monitor的写法, 也就是说可以将lock{ }块中的语句, 放到Monitor的Enter和exit中间
{ //这里就是单线程 this.TotalCount += 1;
TotalCountIn += 1;
this.IntList.Add(newI);
}
Monitor.Exit(btnThreadCore_Click_Lock);

八. 不使用lock解决,线程安全问题:

//使用lock 解决的时候,因为只有一个线程可以操作数据, 没有并发, 所以解决了问题    但是牺牲了性能,所以要尽量缩小lock的范围

//解决办法:1.  开发中最好不要有冲突, 能拆分就优先拆分, 比如在1亿条数据中进行操作, 那么可以先将数据拆分成不同的小块, 然后再合并成1亿条数据

//2. 不使用locak, 可以使用安全队列 System.Collections.Concurrent.ConcurrentQueue来解决,   一个线程去完成操作

  

20181106_线程之异常_取消_变量_安全Lock的更多相关文章

  1. (52)Wangdao.com第七天_字面量/变量_标识符_数据类型_数据的存储

    JavaScript 字面量 和 变量 字面量:就是那些不可变的值,如1,2,100,2000,Infinity,NaN 变量: 变量,代表的当前随机分配的内存地址. 变量的值,是可变的,可以用来保存 ...

  2. 多测师讲解python _函数中变量_高级讲师肖sir

    定义的函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是 被定义为局部变量.在这种情况下,不论全局变量中是否用到该变量名,函数中 使用的都是局部变量.例如: num=100 #全局变量 ...

  3. python学习记录_中断正在执行的代码,执行剪切板中的代码,键盘快捷键,魔术命令,输入和输出变量,记录输入和输出变量_

    2018-03-28 00:56:39 中断正在执行的代码 无论是%run执行的脚本还是长时间运行的命令ctrl + cIn [1]: KeyboardInterrupt 执行剪切板中的代码 ctrl ...

  4. Bash 中的 _ 是不是环境变量

    首先,我们想到的会是 export(等价于 declare -x)命令: $ export | grep 'declare -x _=' 没有找到,那么结论就是 _ 不是环境变量?当然没那么简单,否则 ...

  5. 变量[^_^][T_T]

    变量[^_^][T_T]source .bashrcget_ps1(){if [ "$?" = "0" ]then#we're on the system co ...

  6. Python笔记_第四篇_高阶编程_进程、线程、协程_2.线程

    1. 线程概述: 在一个进程的内部,要同时干多件事情,就需要同时运行“多个子任务”,我们把进程内的这些“子任务”叫做线程.也就说线程是进程成的子任务. 线程通常叫做情景的进程.线程是通过向内侧控件的并 ...

  7. Nginx分时段限制下载速度解决方案(原创)_于堡舰_新浪博客

    Nginx分时段限制下载速度解决方案(原创)_于堡舰_新浪博客 Nginx分时段限制下载速度解决方案(原创)    (2011-03-02 16:40:49)    转载▼    标签:    ngi ...

  8. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  9. Demo02_对结构体进行文件读写_张仕传_作业_

    #include <iostream> using namespace std; #define StructArrarySize 5 // 老师数量 #define StudentNum ...

随机推荐

  1. Django中间件(勾子函数)使用

    中间件 Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django ...

  2. The disadvantage for manager has a part-time job as a trainer

    At present, most companies with in-house trainers take the development model of "full-time trai ...

  3. DataTable和实体类通过反射相互转换

    using System.Runtime.Serialization; using System.Data; using System.Reflection; using System.Collect ...

  4. Linux:ln命令详解(软连接,硬链接)

    ln ln命令用来为文件创件连接,连接类型分为硬连接和软连接(符号连接)两种,默认的连接类型是硬连接.如果要创建软连接必须使用"-s"选项. 硬链接 建立硬链接时,在另外的目录或本 ...

  5. python常用模块之shutil模块

    python常用模块之shutil模块 shutil模块,高级的文件.文件夹.压缩包处理模块 1.shutil.copyfile(src,des[,length]):将文件内容拷贝到另一个文件 In ...

  6. Win10安装Ubuntu16.04 双系统

    Tips: 双系统Ubuntu可以使用机器的GPU硬件,虚拟机不可以 压缩卷留的空间尽量大一点,不要相信50G够用 选UEFI,并关闭 Secure Boot,不要选 Legacy 选UEFI,就要在 ...

  7. CF1083A The Fair Nut and the Best Path

    CF1083A The Fair Nut and the Best Path 先把边权搞成点权(其实也可以不用),那么就是询问树上路径的最大权值. 任意时刻权值非负的限制可以不用管,因为若走路径 \( ...

  8. echarts tooltips宽度设置

    提示文本太长显示不全,设置宽度后:

  9. redis在mac中的安装和启动

    http://blog.csdn.net/chenshuai1993/article/details/51519384 http://www.jianshu.com/p/6b5eca8d908b

  10. vue 中import和export如何一起使用(一)

    前段时间碰到一个问题,vue js中要使用import来加载第三方的js,但是后面使用exports.XXX的话会报exports is not defined.那要怎么解决呢? 首先,我们要了解ES ...