一. 线程的异常处理:

 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. 《Effective C++》第2章 构造/析构/赋值运算(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  2. vs 2013远程调试

    1. 找到本机Remote Debugger/x64文件夹,将其拷贝到远程机器上 2.运行x64文件夹下的msvsmon.exe,将其设置为“无身份验证模式”,记住端口号,一会儿要用到 3.在vs中打 ...

  3. angular 全局 监听路由变化

    app.run(['$rootScope', '$location', function($rootScope, $location) { /* 监听路由的状态变化 */ $rootScope.$on ...

  4. SVN 安装配置详解,包含服务器和客户端,外带一个项目演示,提交,更改,下载历史版本,撤销

    本次要介绍的是svn版本管理工具包含2个: 服务器端:visualsvn server 下载地址为:https://www.visualsvn.com/server/download/   此处演示的 ...

  5. 369C Valera and Elections

    http://codeforces.com/problemset/problem/369/C 树的遍历,dfs搜一下,从根节点搜到每个分叉末尾,记录一下路况,如果有需要修复的,就把分叉末尾的节点加入答 ...

  6. Python环境准备(安装python解释器)

    上篇文章介绍了Python的相关知识,本章就开始着手操作,创建第一个Python程序,在这之前,首先需要配置Python的运行环境,也就是安装python解释器 ------------- 完美的分割 ...

  7. crm 02--->讲师页面及逻辑

    要求: 讲师 批量初始化 考勤 录入成绩 批量初始化 考勤与批量初始化这两个功能都要放在课程记录表中CourseRecord # 批量初始化 # 将该班的所有学生,初始化带某一天,而不是将每个学生一个 ...

  8. Git详解之七 自定义Git

    以下内容转载自:http://www.open-open.com/lib/view/open1328070404827.html自定义 Git 到目前为止,我阐述了 Git 基本的运作机制和使用方式, ...

  9. centos7最小化安装后配置笔记

    一.安装wget(步骤2备用) yum install wget -y 二.切换yum源为阿里云 备份旧源: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum ...

  10. phpcms tag页调用缩略图

    \phpcms\modules\content\tag.php 找到: 'title, description, url, inputtime, style' 改成:'title, thumb, de ...