第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。

一. 传统的线程取消

   所谓的线程取消,就是线程正在执行的过程中取消线程任务。

   传统的线程取消,是通过一个变量来控制,但是这种方式,在release模式下,被优化从cpu高速缓存中读取,而不是从内存中读取,会造成主线程无法执行这一个bug。

复制代码

 1   {2                 var isStop = false;3                 var thread = new Thread(() =>4                 {5                     while (!isStop)6                     {7                         Thread.Sleep(100);8                         Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);9                     }
10                 });
11                 thread.Start();
12                 Thread.Sleep(1000);
13                 isStop = true;
14 }

复制代码

 

PS: 通过上面的代码看可以看出来,传统模式的线程取消,在排除release模式bug的情况下,局限性还是很明显的。比如:当子线程任务取消的那一刻,我想执行另外一项任务;我想延时取消一个线程任务;线程取消的时候抛异常。

  上述这几种情况,我们都要借助单独的类来处理。

 

二. CancellationTokenSource实现任务取消 

1. 取消任务的同时触发一个函数

   利用Cancel方法、Register注册、source.Token标记取消位来实现。

复制代码

            {CancellationTokenSource source = new CancellationTokenSource();//注册一个线程取消后执行的逻辑source.Token.Register(() =>{//这里执行线程被取消后的业务逻辑.Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");});Task.Run(() =>{while (!source.IsCancellationRequested){Thread.Sleep(100);Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);}}, source.Token);Thread.Sleep(2000);source.Cancel();}

复制代码

2. 延时取消

线程的延时取消有两种方式:

  方案一:CancelAfter方法。

复制代码

 1         #region 方案一:CancelAfter方法2                 {3                     CancellationTokenSource source = new CancellationTokenSource();4                     //注册一个线程取消后执行的逻辑5                     source.Token.Register(() =>6                     {7                         //这里执行线程被取消后的业务逻辑.8                         Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");9                     });
10 
11                     Task.Run(() =>
12                     {
13                         while (!source.IsCancellationRequested)
14                         {
15                             Thread.Sleep(100);
16                             Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
17                         }
18                     }, source.Token);
19 
20                     Thread.Sleep(2000);
21                     //4s后自动取消
22                     source.CancelAfter(new TimeSpan(0, 0, 0, 4));
23                 } 
24                 #endregion

复制代码

  方案二:CancellationTokenSource构造函数(不再需要Cancel方法了)。

复制代码

 1                 {2                     //4s后自动取消3                     CancellationTokenSource source = new CancellationTokenSource(4000);4                     //注册一个线程取消后执行的逻辑5                     source.Token.Register(() =>6                     {7                         //这里执行线程被取消后的业务逻辑.8                         Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");9                     });
10 
11                     Task.Run(() =>
12                     {
13                         while (!source.IsCancellationRequested)
14                         {
15                             Thread.Sleep(100);
16                             Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
17                         }
18                     }, source.Token);
19 
20                     Thread.Sleep(2000);
21                 } 

复制代码

 

3. 组合取消

   利用CreateLinkedTokenSource构建CancellationTokenSource的组合体,其中任何一个体取消,则组合体就取消。 

复制代码

            {CancellationTokenSource source1 = new CancellationTokenSource();//source1.Cancel();CancellationTokenSource source2 = new CancellationTokenSource();source2.Cancel();var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);Console.WriteLine("s1={0}  s2={1}  s3={2}", source1.IsCancellationRequested,source2.IsCancellationRequested,combineSource.IsCancellationRequested);}

复制代码

  上述代码,source1和source2中的任何一个取消,combineSource就会被取消。

 

三. CancellationToken类监控取消

   CancellationToken类下ThrowIfCancellationRequested属性,等价于if (XXX.IsCancellationRequested){throw new Exception("报错了");}

   只要取消就报错。

复制代码

 1             {2                 CancellationTokenSource source1 = new CancellationTokenSource();3                 CancellationTokenSource source2 = new CancellationTokenSource();4                 var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);5                 source1.Cancel();6 7                 //if (combineSource.IsCancellationRequested)8                 //{9                 //    throw new Exception("报错了");
10                 //}
11 
12                 //等价于上面那句话
13                 try
14                 {
15                     combineSource.Token.ThrowIfCancellationRequested();
16                 }
17                 catch (Exception)
18                 {
19                     Console.WriteLine("报错了");
20                 }
21 
22 
23                 Console.WriteLine("s1={0}  s2={1}  s3={2}", source1.IsCancellationRequested,
24                                                          source2.IsCancellationRequested,
25                                                          combineSource.IsCancellationRequested);
26             }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

start()和run()的区别

start方法: 通过该方法启动线程的同时也创建了一个线程,真正实现了多线程。无需等待run()方法中的代码执行完毕,就可以接着执行下面的代码。此时start()的这个线程处于就绪状态,当得到CPU的时间片后就会执行其中的run()方法。这个…

c#中的BeginInvoke和EndEndInvoke 摘要

摘要 异步这东西,真正用起来的时候,发现事情还是挺多的,最近在项目中用到了异步的知识,发现对它还是不了解,处理起来,走了不少弯路。觉得还是补一补还是很有必要的。 MSDN原文地址:https://ms…

关于@DateTimeFormat 和 @JsonFormat 注解

两个参数都是针对日期格式化做处理 1.入参格式化DateTimeFormat 传入参数是 String 类型,接收的参数Date 类型,类型无法转换。 使用 Spring 的 DateTimeFormat 注解格式化参数 传入参数要是日期格式的String 类型 例如:"2021-10-01" pattern &quo…

NET 提供了执行异步操作的三种模式

1.APM模式简介 在.net1.x的版本中就可以使用IAsyncResult接口实现异步操作,但是比较复杂,这种称之为异步编程模型模式 (Asynchronous Programming Model, APM),也称为IAsyncResult模式 在这种APM模式下,一个同步操作XXX需要定义B…

java实体类属性非空判断工具类

import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry;public class CheckParametersUtil {Map<String, Object> map new HashMap<>();/*** 添加需要校验的参数* param object 实参* param parameterName 参…

第八节:Task的各类TaskTResult返回值以及通用线程的异常处理方案。

一. Task的各种返回值-Task<TResult> PS&#xff1a; 在前面章节&#xff0c;我们介绍了Task类开启线程、线程等待、线程延续的方式&#xff0c;但我们并没有关注这些方式的返回值&#xff0c;其实他们都是有返回值的Task<TResult>&#xff0c;然后可以通过Task的…

第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程&#xff1a;所谓的串行编程就是单线程的作用下&#xff0c;按顺序执行。(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程&#xff1a;充分利用多核cpu的优势&#xff0c;同时开启多个线程并行执行。(典型代表…

Mybatis四种分页方式

1.数组分页 查询出全部数据&#xff0c;然后再list中截取需要的部分。 mybatis接口 List<Student> queryStudentsByArray(); xml配置文件 <select id"queryStudentsByArray" resultMap"studentmapper">select * from student</select&…

第十节:利用async和await简化异步编程模式的几种写法

一. async和await简介 PS&#xff1a;简介 1. async和await这两个关键字是为了简化异步编程模型而诞生的&#xff0c;使的异步编程更简洁&#xff0c;它本身并不创建新线程&#xff0c;但在该方法内部开启多线程&#xff0c;则另算。 2. 这两个关键字适用于处理一些文件IO操作。…

第十一节:深究用户模式锁的使用场景(异变结构、互锁、旋转锁)

一. 锁机制的背景介绍 本章节&#xff0c;将结合多线程来介绍锁机制&#xff0c; 那么问题来了&#xff0c;什么是锁呢&#xff1f; 为什么需要锁&#xff1f; 为什么要结合多线程来介绍锁呢&#xff1f;锁的使用场景又是什么呢&#xff1f; DotNet中又有哪些锁呢&#xff1f; …

第十三节:实际开发中使用最多的监视锁Monitor、lock语法糖的扩展、混合锁的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)

一. 监视锁(Monitor和lock) 1. Monitor类&#xff0c;限定线程个数的一把锁&#xff08;Synchronized lock是他的语法糖&#xff09;&#xff0c;两个核心方法&#xff1a; Enter&#xff1a;锁住某个资源。 Exit&#xff1a;退出某一个资源。 测试案例&#xff1a;开启5个线…

什么是Mybatis ?

使用JDBC连接数据库 半自动持久层的ORM框架(因为要自己手写sql) 可以使用xml配置,可以使用注解. 优点:1.低耦合,sql重用,编写灵活 2.减少冗余代码 3.兼容数据库 4.能很好的与spring集成 5.提供映射标签,支持对象与数据库的ORM字段映射 缺点:1.sql需要自己编写 2数据库移植性…

第十四节: 介绍四大并发集合类并结合单例模式下的队列来说明线程安全和非安全的场景及补充性能调优问题。

一. 四大并发集合类 背景&#xff1a;我们目前使用的所有集合都是线程不安全的 。 A. ConcurrentBag&#xff1a;就是利用线程槽来分摊Bag中的所有数据&#xff0c;链表的头插法,0代表移除最后一个插入的值. (等价于同步中的List) B. ConcurrentStack&#xff1a;线程安全的St…

#{} 跟${}的区别

#{}是预编译处理 ,可以防止sql注入 ,提高安全性 mybatis 会把sql中的#{}替换成? 调用PreparedStatement set方法赋值 ${}是字符串替换 mybatis会把${}直接替换成变量值

第十五节:深入理解async和await的作用及各种适用场景和用法

一. 同步VS异步 1. 同步 VS 异步 VS 多线程 同步方法&#xff1a;调用时需要等待返回结果&#xff0c;才可以继续往下执行业务 异步方法&#xff1a;调用时无须等待返回结果&#xff0c;可以继续往下执行业务 开启新线程&#xff1a;在主线程之外开启一个新的线程去执行业…

@PostConstruct注解

PostConstruct是Java自己的注解. PostConstruct该注解被用来修饰一个非静态的void()方法. PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次. PostConstruct在构造函数之后执行,init()方法之前执行. 执行顺序 Constructor >> Autow…

springCloud五大组件--Gateway

SpringCloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等技术开发的网关&#xff0c;它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 Spring Cloud Gateway 的目标&#…

多线程篇(被替换)

一. 背景 在刚接触开发的头几年里&#xff0c;说实话&#xff0c;根本不考虑多线程的这个问题&#xff0c;貌似那时候脑子里也有没有多线程的这个概念&#xff0c;所有的业务都是一个线程来处理&#xff0c;不考虑性能问题&#xff0c;当然也没有考虑多线程操作一条记录存在的并…

springCloud五大组件--Eureka

Spring Cloud 支持了 Zookeeper、Consul 和 Eureka&#xff0c;官方推荐 Eureka。 C(一致性)A(高可用)P(分区容错)理论&#xff0c;Eureka的选择就是放弃C&#xff0c;选择AP。 Eureka 采用纯 Java 实现&#xff0c;除实现了注册中心基本的服务注册和发现之外&#xff0c;极大…

.NET异步程序设计之任务并行库

目录 1.简介2.Parallel类 2.0 Parallel类简介2.1 Parallel.For()2.2 Parallel.ForEach()2.3 Parallel.Invoke()2.4 补充&#xff1a;线程安全集合3.Task类 3.0 Task类简介3.1 创建无返回值的Task任务3.2 创建有返回值的Task任务3.3 为Task添加延续任务3.4 Task.Delay3.5 Task对…