在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托源码

一、异步、同步

1.同步(在计算的理解总是要你措不及防,同步当线程做完一件事情之后,才会执行后续动作),同步方法慢,只有一个线程执行,异步方法快,因为多个线程一起干活,但是两者并不是线性增长,当我们的异步线程占有的资源越来越多了,会导致资源可能不够,其次线程过多CPU也是需要管理成本的,所以不是越多越好。

2.异步(可以同时执行多个任务,在同样的时间,执行不同的任务),同步方法卡界面(UI),因为我们的主线程(UI)忙于计算造成了堵塞了。异步方法不卡界面,计算任务交给了子线程完成。winform中体现的玲玲精致。(你品,你细品),web 可以异步的处理一起其他的任务,比如给用户发邮箱(我们的BS结构的,每次访问都是一个子线程,当我们的代码写的比较糟糕,是不是加载比较慢呢哈哈)。异步多线程无序,执行的先后无序,执行的时间不确定,结束也不确定,所以我们很难通过执行时间和先后顺序控制,异步的执行顺序。

二、初识Thread

属性名称 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,该值指示线程的调度优先级。
ThreadState 获取一个值,该值包含当前线程的状态。

Thread 中包括了多个方法来控制线程的创建、挂起、停止、销毁,后面的例子中会经常使用。

方法名称 说明
Abort()     终止本线程。
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start()   执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep()   把正在运行的线程挂起一段时间。

1.Thread是我们.NET 1.0 给我们提供的多线程类,可以创建,和控制多线程,Thread类构造函数为接受ThreadStart和ParameterizedThreadStart类型的委托参数,下面有请代码神君。

        /// <summary>
/// 使用Thread 创建多线程
/// </summary>
public static void Show()
{
//实例化创建线程 无参无返回值
Thread thread = new Thread(() =>
{
Console.WriteLine("我是多线程");
});
thread.Start(); //创建5个线程1
for (int i = ; i < ; i++)
{
//这个之所以创建一个k,后面线程不安全会说到
var k = i;
//这是一个有参数无返回值多线程
new Thread(x => Running(Convert.ToInt32(x))).Start(k);
}
Console.Read();
} /// <summary>
/// 一个执行需要长时间的任务
/// </summary>
static void Running(int s)
{
Console.WriteLine("**********************************");
Console.WriteLine("执行开始啦" + s);
Console.WriteLine("获取当前执行的线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
var j = ;
for (int i = ; i < ; i++)
{
j++;
}
Console.WriteLine("执行结束啦" + s);
}

二、渐入佳境

  1.运行上面的代码,可以看到线程的无序性,虽然我们的0最先开始执行的,但是不是第一个结束的,这个是因为我们每个线程执行的时间的不确定性。这里也要特别说明为什么Thread构造函数传递的是ThreadStart和ParameterizedThreadStart类型的委托参数,为什么不是Action ,Func,答案就是.NET 1.0的时候还没有Action 、Func。ThreadStart委托是一个无参无返回值上代码中我们创建了,ParameterizedThreadStart委托是一个有参数无返回值,但是我们可以看到我们的参数是一个object类型,是一个不安全的参数(当时泛型也没有出来)当然为了防止这问题,我们也是想到了方法,那就是我们可以通过一个泛型类,帮我们限制参数类型。

        /// <summary>
/// 防止参数不安全
/// </summary>
public static void Show5()
{
//我们创建一个泛型类,限制我们的类型
MyThread<string> mythread = new MyThread<string>("Thread_child");
//将我们的方法传递,进去
Thread th3 = new Thread(mythread.ThreadChild);
//启动线程
th3.Start();
} /// <summary>
/// 创建一个泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
class MyThread<T>
{
private T data;
public MyThread(T data)
{
this.data = data;
}
public void ThreadChild()
{
Console.WriteLine("Child Thread Start! Result:{0}", data);
}
}

  2.我们在上面还提供了其他的方法,但是这些方法已经不建议使用了,现在已经弃用了,因为我们无法精确地控制线程的开启与暂停,当我们将线程挂起的时候,同时也会挂起线程使用的资源,会导致死锁,不建议使用。将线程销毁也不建议    不一定及时/有些动作发出收不回来。(这里我使用的是.net Core 3.1 执行直接报错了哈哈)

        /// <summary>
/// 使用Thread 线程挂起、唤醒线程、销毁,方式是抛异常、取消Abort异常
/// </summary>
public static void Show1()
{
//创建一个Thread 线程
Thread thread = new Thread(() =>
{
Running();
});
//开启线程
thread.Start();
//这个是线程挂起
//thread.Suspend();
//唤醒线程
//thread.Resume();
//上面的两个方法,现在已经弃用了,因为我们无法精确地控制线程的开启与暂停
//当我们将线程挂起的时候,同时也会挂起线程使用的资源,会导致死锁,不建议使用
try
{
//将线程销毁
//也不建议 不一定及时/有些动作发出收不回来
thread.Abort();
}
catch (Exception)
{
//静态方法将线程异常取消继续工作
Thread.ResetAbort();
}
Console.Read();
}

  3.线程优先级,当然我们的线程是一个无序的,也有控制线程执行的权重,但是这个优先级不是绝对的,因为线程的执行顺序还是看我们的CPU爸爸的,但是我们可以利用Priority属性做线程的权重执行,使用也很简单

  /// <summary>
/// 使用Thread 线程的优先级(但是执行还是看CPU,可以做优先级,但是不是绝对优先)
/// </summary>
public static void Show3()
{
//创建一个Thread 线程
Thread thread = new Thread(() =>
{
Running();
});
thread.Start();
//thread.Priority属性可以设置线程的优先级关系
thread.Priority = ThreadPriority.Highest;
Console.WriteLine("执行完啦啦啦啦啦啦啦啦啦啦啦拉拉");
Console.Read();
}

  4.前台线程、后台线程(这个字面意思,还是和我们的理解是不一样的)我们设置IsBackground控制线程是否(前/后)台线程。默认是前台线程,启动之后一定要完成任务的,阻止进程退出。指定后台线程:随着进程退出。

 三、多线程起飞

  1、异步回调

    1.我们的Thread没有给我提供异步回调的功能,没办法需要自己造轮子了,我们可以先想一下回调的需求是什么,需求分析:当我们的线程任务执行完之后需要之后某些方法。我们细品一下,我们要执行完之后,在执行一个人任务,那就是同步执行异步方法了吧。我们在子线程中怎么同步执行呢?下面的代码就实现了回调功能不管我们执行多少次回调总会在任务后面执行。

/// <summary>
/// 异步回调执行
/// </summary>
public static void Show6() {
//创建一个任务委托
ThreadStart threadStart = () => {
Console.WriteLine("我是任务");
};
//创建一个回调执行的委托
Action action = () => {
Console.WriteLine("哈哈,我就是你们的回调方法哈,记得双击么么哒");
Console.WriteLine("*********************************************");
};
ThreadWithCallback(threadStart, action);
Console.ReadLine();
} /// <summary>
/// 回调封装 无返回值
/// </summary>
/// <param name="start"></param>
/// <param name="callback">回调</param>
private static void ThreadWithCallback(ThreadStart start, Action callback)
{
Thread thread = new Thread(() =>
{
start.Invoke();
callback.Invoke();
});
thread.Start();
}

  2、返回参数

    1.当然我们使用线程需要返回参数,但是我们的Thread没有给我们提供返回值的委托和方法,这个要莫子搞罗?当然我们先分析需求,我们要获取返回值是不是要等线程执行之后呢?好的线程执行我们可以使用Join堵塞线程等它执行完毕,但是我们要怎么获取返回值呢?对了我们可以创建一个变量,我们的线程给变量赋值吗?

/// <summary>
/// 异步返回值
/// </summary>
public static void Show7()
{
//创建一个委托
Func<string> func = () => {
return "我是返回值";
};
//获取执行结果
Console.WriteLine(ThreadWithReturn(func).Invoke());
Console.ReadLine();
} /// <summary>
/// 有返回值封装(请根据本案例自行封装回调)
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="func">需要子线程执行的方法</param>
/// <returns></returns>
private static Func<T> ThreadWithReturn<T>(Func<T> func)
{
//初始化一个泛型,限制我们的类型
T t = default(T);
ThreadStart newStart = () =>
{
//线程给变量赋值
t = func.Invoke();
};
//创建线程
Thread thread = new Thread(newStart);
//执行线程
thread.Start();
//创建一个委托 无参有返回值,执行委托会发生执行线程等待堵塞
//当线程执行完之后,也就是说线程已经给变量t赋值了,我们就返回t
return new Func<T>(() =>
{
thread.Join();
return t;
});
}

 四、Thread总结

  1.大家是不是觉得多线程很酷呢?哈哈我刚刚学的时候也是激动的心颤抖的手。当然文章中我们介绍了很多API的使用,大家可以动手试试,API的使用是小事,最重要的是我们的思路,到我们看到回调封装和返回值封装,我们都是利用了多线程的一些特性,来完成的这些功能拓展的。我们宏观的看多线程感觉很恐怖,但是在我们做回调函数的时候是不是感觉有一种微观看法,线程执行的内部也是同步的执行哪些方法的。好了今天就写到这里昨天晚上9点多就睡了,早起撸个文章美滋滋。当然多线程还有讲完的,才说道了.NET 1.0哈哈,后续的文章也会写出来。

多线程之旅(Thread)的更多相关文章

  1. C#多线程之旅(3)——线程池

    v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...

  2. C#多线程之旅(1)——介绍和基本概念

    原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...

  3. C#多线程之旅(7)——终止线程

    先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很多问题.   ...

  4. C#多线程之旅(4)——APM初探

    源码地址:https://github.com/Jackson0714/Threads 原文地址:C#多线程之旅(4)——APM初探 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C# ...

  5. Java多线程4:Thread中的静态方法

    一.Thread类中的静态方法 Thread类中的静态方法是通过Thread.方法名来调用的,那么问题来了,这个Thread指的是哪个Thread,是所在位置对应的那个Thread嘛?通过下面的例子可 ...

  6. “全栈2019”Java多线程第二章:创建多线程之继承Thread类

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. 2018.3.3 多线程中继承Thread 和实现Runnable接口 的比较(通过售票案例来分析)

    多线程中继承Thread 和实现Runnable接口 的比较(通过售票案例来分析) 通过Thread来实现 Test.java package com.lanqiao.demo4; public cl ...

  8. 【C#多线程】1.Thread类的使用及注意要点

    Thread随便讲讲 因为在C#中,Thread类在我们的新业务上并不常用了(因为创建一个新线程要比直接从线程池拿线程更加耗费资源),并且在.NET4.0后新增了Task类即Async与await关键 ...

  9. Java多线程专题3: Thread和ThreadLocal

    合集目录 Java多线程专题3: Thread和ThreadLocal 进程, 线程, 协程的区别 进程 Process 进程提供了执行一个程序所需要的所有资源, 一个进程的资源包括虚拟的地址空间, ...

随机推荐

  1. Js对于数组去重提高效率一些心得

    最近在找工作,好几次面试都问过数组去重的问题.虽然问的都不一样,但是核心思想是没有变的. 第一种是比较常规的方法 思路: 构建一个新的数组存放结果 for循环中每次从原数组中取出一个元素,用这个元素循 ...

  2. 给你的Kubernetes集群建一个只读账户(防止高管。。。后)

    给你的Kubernetes集群建一个只读账户 需求:我们知道搭完k8s集群会创建一个默认的管理员kubernetes-admin用户该用户拥有所以权限,有一天开发或测试的同学需要登录到k8s集群了解业 ...

  3. 制作UEFI(64位)下的WinPE + Ubuntu + Acronis多启动U盘

    最近研究了一下如何制作一个多启动U盘,其中想包含的功能是WinPE(这里选择WEPE),Ubuntu 18.04,Acronis True Image 2018的ISO恢复盘.这里分享一下制作的经验和 ...

  4. Windows Server 2012搭建SQL Server Always On踩坑全记录

    Windows Server 2012搭建SQL Server Always On踩坑全记录 环境信息: Windows Server 2012 R2 Sql Server 2012 整个搭建集群的过 ...

  5. VUE实现Studio管理后台(一):鼠标拖放改变窗口大小

    近期改版RXEditor,把改版过程,用到的技术点,记录下来.昨天完成了静态页面的制作,制作过程并未详细记录,后期已经不愿再补了,有些遗憾.不过工作成果完整保留在github上,地址:https:// ...

  6. pip install mysqlclient报错(OSError: mysql_config not found)

    报错截图 一般情况是系统没有安装libmysqld-dev 执行 sudo apt install libmysqld-dev完成安装后再 pip install mysqlclient就可以了(系统 ...

  7. 【DirectX 11学习笔记】世界矩阵的理解-运动合成

    最近在看龙书,写一下自己的学习理解,主要是物体运动的合成. 物体于局部坐标系内构建,每个物体拥有自己的局部坐标系以及相应的顶点矩阵A,并通过世界矩阵变换到唯一的世界坐标系. 物体在某时刻发生了位移和旋 ...

  8. 【渗透】node.js经典问题

    1.循环问题 当循环调用 require() 时,一个模块可能在未完成执行时被返回.例如以下情况:a.js: exports.done = false; const b = require('./b. ...

  9. Postgresql存放数组形式的数据

    Postgres 数据库允许把字段定义为可变长度的数组.数据类型既可以是内置类型,也可以是用户自定义的类型或枚举类型. 例如: 创建表 create table demo(name text,subj ...

  10. Pytorch-Tensor基本操作

    (此文为个人学习pytorch时的笔记,便于之后的查询) Tensor基本操作 创建tensor: ​ 1.numpy向量转tensor: a=np.array([2,2,2]) b=torch.fr ...