第二节:深入剖析Thread的五大方法、数据槽、内存栅栏

一. Thread及其五大方法

   Thread是.Net最早的多线程处理方式,它出现在.Net1.0时代,虽然现在已逐渐被微软所抛弃,微软强烈推荐使用Task(后面章节介绍),但从多线程完整性的角度上来说,我们有必要了解下N年前多线程的是怎么处理的,以便体会.Net体系中多线程处理方式的进化。

  Thread中有五大方法,分别是:Start、Suspend、Resume、Intterupt、Abort

  ①.Start:开启线程

  ②.Suspend:暂停线程

  ③.Resume:恢复暂停的线程

  ④.Intterupt:中断线程(会抛异常,提示线程中断)

  ⑤.Abort:销毁线程

    这五大方法使用起来,也比较简单,下面贴一段代码,体会一下如何使用即可。

 

  在这里补充一下,在该系列中,很多测试代码中看到TestThread0、TestThread、TestThread2,分别对应无参、一个参数、两个参数的耗时方法,代码如下:

 View Code

 

二. 从源码角度分析Thread类

(1)  分析Thread类的源码,发现其构造函数有两类,分别是ThreadStart和ParameterizedThreadStart类,

 其中

  ①:ThreadStart类,是无参无返回值的委托。

  ②:ParameterizedThreadStart类,是有一个object类型参数但无返回值的委托.

使用方法:

  ①:针对ThreadStart类, ThreadStart myTs = () => TestThread(name);  然后再把myTs传入Thread的构造函数中

  ②:针对ParameterizedThreadStart类,ParameterizedThreadStart myTs = o => this.TestThread(o.ToString());  然后再把myTs传入Thread的构造函数中

  注:该方式存在拆箱和装箱的转换问题,不建议这么使用

通用写法

     Thread t = new Thread(() =>

    {

       Console.Write("333");

    });

    t.Start();

无须考虑Thread的构造函数,也不需要考虑Start的时候传参,直接使用()=>{}的形式,解决一切问题。

(二) 前台进程和后台进程(IsBackground属性)

  ①:前台进程,Thread默认为前台线程,程序关闭后,线程仍然继续,直到计算完为止

  ②:后台进程,将IsBackground属性设置为true,即为后台进程,主线程关闭,所有子线程无论运行完否,都马上关闭

(三) 线程等待(Join方法)

  利用Join方法实现主线程等待子线程,当多个子线程进行等待的时候,只能通过for循环来实现

 下面贴一下这三块设计到的代码:

 

 View Code

(四). 扩展:Thread实现线程回调

 

三. 数据槽-线程可见性

  背景:为了解决多线程竞用共享资源的问题,引入数据槽的概念,即将数据存放到线程的环境块中,使该数据只能单一线程访问.(属于线程空间上的开销)

  下面的三种方式是解决多线程竞用共享资源的通用方式:

  ①:AllocateNamedDataSlot命名槽位和AllocateDataSlot未命名槽位 解决线程竞用资源共享问题。

  (PS:在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问)

 

   private void button10_Click(object sender, EventArgs e){#region 01-AllocateNamedDataSlot命名槽位{var d = Thread.AllocateNamedDataSlot("userName");//在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问Thread.SetData(d, "ypf");//声明一个子线程var t1 = new Thread(() =>{Console.WriteLine("子线程中读取数据:{0}", Thread.GetData(d));});t1.Start();//主线程中读取数据Console.WriteLine("主线程中读取数据:{0}", Thread.GetData(d));}#endregion#region 02-AllocateDataSlot未命名槽位{var d = Thread.AllocateDataSlot();//在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问Thread.SetData(d, "ypf");//声明一个子线程var t1 = new Thread(() =>{Console.WriteLine("子线程中读取数据:{0}", Thread.GetData(d));});t1.Start();//主线程中读取数据Console.WriteLine("主线程中读取数据:{0}", Thread.GetData(d));}#endregion}

 

  ②:利用特性[ThreadStatic] 解决线程竞用资源共享问题

   (PS:在主线程中给ThreadStatic特性标注的变量赋值,则只有主线程能访问该变量)

  ③:利用ThreadLocal线程的本地存储, 解决线程竞用资源共享问题(线程可见性)

  (PS: 在主线程中声明ThreadLocal变量,并对其赋值,则只有主线程能访问该变量)

 

 

四. 内存栅栏-线程共享资源

背景:当多个线程共享一个变量的时候,在Release模式的优化下,子线程会将共享变量加载的cup Cache中,导致主线程不能使用该变量而无法运行。

解决方案:

  ①:不要让多线程去操作同一个共享变量,从根本上解决这个问题。

  ②:利用MemoryBarrier方法进行处理,在此方法之前的内存写入都要及时从cpu cache中更新到 memory;在此方法之后的内存读取都要从memory中读取,而不是cpu cache。

  ③:利用VolatileRead/Write方法进行处理。

复制代码

 1  private void button11_Click(object sender, EventArgs e)2         {3             #region 01-默认情况(Release模式主线程不能正常运行)4             //{5             //    var isStop = false;6             //    var t = new Thread(() =>7             //    {8             //        var isSuccess = false;9             //        while (!isStop)
10             //        {
11             //            isSuccess = !isSuccess;
12             //        }
13             //        Console.WriteLine("子线程执行成功");
14             //    });
15             //    t.Start();
16 
17             //    Thread.Sleep(1000);
18             //    isStop = true;
19 
20             //    t.Join();
21             //    Console.WriteLine("主线程执行结束");
22             //}
23             #endregion
24 
25             #region 02-MemoryBarrier解决共享变量(Release模式下可以正常运行)
26             //{
27             //    var isStop = false;
28             //    var t = new Thread(() =>
29             //    {
30             //        var isSuccess = false;
31             //        while (!isStop)
32             //        {
33             //            Thread.MemoryBarrier();
34 
35             //            isSuccess = !isSuccess;
36             //        }
37             //        Console.WriteLine("子线程执行成功");
38             //    });
39             //    t.Start();
40 
41             //    Thread.Sleep(1000);
42             //    isStop = true;
43 
44             //    t.Join();
45             //    Console.WriteLine("主线程执行结束");
46             //}
47             #endregion
48 
49             #region 03-VolatileRead解决共享变量(Release模式下可以正常运行)
50             {
51                 var isStop = 0;
52                 var t = new Thread(() =>
53                 {
54                     var isSuccess = false;
55                     while (isStop == 0)
56                     {
57                         Thread.VolatileRead(ref isStop);
58 
59                         isSuccess = !isSuccess;
60                     }
61                     Console.WriteLine("子线程执行成功");
62                 });
63                 t.Start();
64 
65                 Thread.Sleep(1000);
66                 isStop = 1;
67 
68                 t.Join();
69                 Console.WriteLine("主线程执行结束");
70             }
71             #endregion
72 
73 
74         }

 

 

 

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

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

相关文章

java redis 生成唯一id_Redis在集群环境中生成唯一ID

概述设计目标:每秒最大生成10万个ID,ID单调递增且唯一。Reidis可以不需要持久化ID。要求:集群时钟不能倒退。总体思路:集群中每个节点预生成生成ID;然后与redis的已经存在的ID做比较。如果大于,则取节点生成的ID&#…

java await signal_【Java并发008】原理层面:ReentrantLock中 await()、signal()/signalAll()全解析...

一、前言上篇的文章中我们介绍了AQS源码中lock方法和unlock方法,这两个方法主要是用来解决并发中互斥的问题,这篇文章我们主要介绍AQS中用来解决线程同步问题的await方法、signal方法和signalAll方法,这几个方法主要对应的是synchronized中的…

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

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

mysql2005触发器修改成绩_创建、更改和删除触发器

创建、更改和删除触发器Creating, Altering, and Removing Triggers08/06/2017本文内容适用于&#xff1a;Applies to: SQL ServerSQL Server(所有支持的版本)SQL ServerSQL Server (all supported versions) Azure SQL 数据库Azure SQL DatabaseAzure SQL 数据库Azure SQL Dat…

第一节:从面向对象思想(oo)开发、接口、抽象类以及二者比较

一. 面向对象思想 1. 面向过程&#xff08;OP&#xff09;和面向对象&#xff08;OO&#xff09;的区别&#xff1a; (1)&#xff1a;面向过程就是排着用最简单的代码一步一步写下去&#xff0c;没有封装&#xff0c;当业务复杂的时候&#xff0c;改动就很麻烦了 (2)&#xff…

第二节:重写(new)、覆写(overwrite)、和重载(overload)

一. 重写 1. 关键字&#xff1a;new 2. 含义&#xff1a;子类继承父类中的普通方法&#xff0c;如果在子类中重写了一个和父类中完全相同的方法&#xff0c;子类中会报警告(问是否显式的隐藏父类的中的方法)&#xff0c;如果在子类中的方法前加上new关键字&#xff0c;则警告…

java 分页查询_JavaWeb之分页查询

时间&#xff1a;2016-12-11 01:411、分页的优点&#xff1a;只查询一页&#xff0c;不需要查询所有数据&#xff0c;能够提高效率。2、分页数据页面的数据都是由Servlet传递的* 当前页&#xff1a;pageCode> 如果页面没有向Servlet传递页码&#xff0c;那么Servlet默认…

第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字

一. 各类数据结构比较及其线程安全问题 1. Array(数组)&#xff1a; 分配在连续内存中,不能随意扩展&#xff0c;数组中数值类型必须是一致的。数组的声明有两种形式&#xff1a;直接定义长度&#xff0c;然后赋值&#xff1b;直接赋值。 缺点&#xff1a;插入数据慢。 优点&a…

第四节:IO、序列化和反序列化、加密解密技术

一. IO读写   这里主要包括文件的读、写、移动、复制、删除、文件夹的创建、文件夹的删除等常规操作。 注意&#xff1a;这里需要特别注意&#xff0c;对于普通的控制台程序和Web程序&#xff0c;将"相对路径"转换成"绝对路径"的方法不一致。 (1). 在w…

java mediator_java—mediator中介模式

中介者模式是由GoF提出的23种软件设计模式的一种。Mediator模式是行为模式之一&#xff0c;Mediator模式定义:用一个中介者对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立的改变他们之间的交互。适用性…

第五节:泛型(泛型类、接口、方法、委托、泛型约束、泛型缓存、逆变和协变)

一. 泛型诞生的背景 在介绍背景之前&#xff0c;先来看一个案例&#xff0c;要求&#xff1a;分别输出实体model1、model2、model3的id和name值,这三个实体有相同的属性名字id和name。 1 public class myUtils2 {3 //要求&#xff1a;分别输出实体model1、model2、…

第六节:反射(几种写法、好处和弊端、利用反射实现IOC)

一. 加载dll,读取相关信息 1. 加载程序集的三种方式 调用Assembly类下的三个方法&#xff1a;Load、LoadFile、LoadFrom。 1       //1.1 Load方法&#xff1a;动态默认加载当前路径下的(bin)下的dll文件,不需要后缀 2 Assembly assembly Assembly.Load(&…

第七节:语法总结(1)(自动属性、out参数、对象初始化器、var和dynamic等)

一. 语法糖简介 语法糖也译为糖衣语法&#xff0c;是由英国计算机科学家彼得约翰兰达&#xff08;Peter J. Landin&#xff09;发明的一个术语&#xff0c;指计算机语言中添加的某种语法&#xff0c;这种语法对语言的功能并没有影响&#xff0c;但是更方便程序员使用。通常来说…

java不用插件播放媒体文件_java servlet不用插件上传文件:

展开全部import java.net.*;import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;public class SaveFileServlet extends HttpServlet{FileWriter savefile;String filename null;String value null;/*** Handles a POST request*/publ…

第八节:语法总结(2)(匿名类、匿名方法、扩展方法)

一. 匿名类 1. 传统的方式给类赋值&#xff0c;需要先建一个实体类→实例化→赋值&#xff0c;步骤很繁琐&#xff0c;在.Net 3.0时代&#xff0c;微软引入匿名类的概念&#xff0c;简化了代码编写&#xff0c;提高了开发效率。 匿名类的声明语法&#xff1a; var objnew {字段…

第九节:委托和事件(1)(委托的发展历史、插件式编程、多播委托)

一. 委托的发展历史和基本用法 说起委托&#xff0c;每个人可能都会对他有不同的理解&#xff0c;结合实战中委托的使用&#xff0c;我对其理解是&#xff1a;委托和类一样&#xff0c;是用户的一个自定义类型&#xff0c;委托可以有参数、有返回值&#xff0c;委托的关键字是d…

第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)

一. 泛型委托 所谓的泛型委托&#xff0c;即自定义委托的参数可以用泛型约束&#xff0c;同时内置委托Func和Action本身就是泛型委托。 将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下。 1 public class Calculator22 {3 //传统解决方案一&am…

java+sm4+加密算法_SM4加密算法实现Java和C#相互加密解密

https://www.cnblogs.com/miaoziblog/p/9040473.html近期由于项目需要使用SM4对数据进行加密&#xff0c;然后传给Java后台&#xff0c;Java后台使用的也是SM4的加密算法但是就是解密不正确&#xff0c;经过一步步调试发现Java中好多数据类型与C#的相同的数据类型是存在不同的比…

DotNet进阶系列

一. 回顾历史 回顾个人发展历程&#xff0c;自2012年初次接触开发至今(2018年)已经有六个年头&#xff0c;这期间陆陆续续学习并掌握了不少技术&#xff0c;C#语言、ORM框架、多线程技术、设计模式、前端技术、MVC、MVVM框架思想等等&#xff0c;每种技术随着多次使用&#xff…

第十一节:特性(常见的特性标签、自定义特性、特性的使用案例)

一. 基本概念 1. 什么是特性? MSDN官方给出的定义时&#xff1a;公共语言运行时允许添加类似关键字的描述声明&#xff0c;叫做特性&#xff0c;它对程序中的元素进行标注&#xff0c;如类型、字段、方法和属性等。Attribute和Microsoft .Net Framework文件的元数据&#xff…