多线程之旅(Thread)
在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托。源码
一、异步、同步
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)的更多相关文章
- C#多线程之旅(3)——线程池
v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...
- C#多线程之旅(1)——介绍和基本概念
原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...
- C#多线程之旅(7)——终止线程
先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很多问题. ...
- C#多线程之旅(4)——APM初探
源码地址:https://github.com/Jackson0714/Threads 原文地址:C#多线程之旅(4)——APM初探 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C# ...
- Java多线程4:Thread中的静态方法
一.Thread类中的静态方法 Thread类中的静态方法是通过Thread.方法名来调用的,那么问题来了,这个Thread指的是哪个Thread,是所在位置对应的那个Thread嘛?通过下面的例子可 ...
- “全栈2019”Java多线程第二章:创建多线程之继承Thread类
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 2018.3.3 多线程中继承Thread 和实现Runnable接口 的比较(通过售票案例来分析)
多线程中继承Thread 和实现Runnable接口 的比较(通过售票案例来分析) 通过Thread来实现 Test.java package com.lanqiao.demo4; public cl ...
- 【C#多线程】1.Thread类的使用及注意要点
Thread随便讲讲 因为在C#中,Thread类在我们的新业务上并不常用了(因为创建一个新线程要比直接从线程池拿线程更加耗费资源),并且在.NET4.0后新增了Task类即Async与await关键 ...
- Java多线程专题3: Thread和ThreadLocal
合集目录 Java多线程专题3: Thread和ThreadLocal 进程, 线程, 协程的区别 进程 Process 进程提供了执行一个程序所需要的所有资源, 一个进程的资源包括虚拟的地址空间, ...
随机推荐
- oracle监控参数
Sar –u 检查CPU的繁忙程度列说明Usr用户模式下cpu运行所占的百分比Sys系统模式下cpu运行所占的百分比Wio因为有进程等待块I/O而使cpu处于闲置状态所占百分比IdleCpu为闲置状态 ...
- IIS+PHP+Mysql 返回500,服务器内部资源问题
这个错误困扰了我好久.... 尝试了好多方法都不管用,最后突然发现我的代码是: <?php $link=mysql_connect("localhost","xxx ...
- C++走向远洋——63(项目二2、两个成员的类模板)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- 初学Qt——QTableView+QSqlqueryModel
我们在显示报表时可以用到上面两个类来实现,QTableView负责对视图显示:QSqlqueryModel则负责数据模块. 这里数据查询使用QSqlqueryModel主要是这个类可以通过自己写的查询 ...
- git指令-工作区和暂存区
#git指令-工作区和暂存区 工作区(Working Directory):就是平常电脑可以看到的文件夹目录 版本库(Repository):存放git内容的文件夹例如: Git的版本库里存了很多东西 ...
- 从0开发3D引擎(十):使用领域驱动设计,从最小3D程序中提炼引擎(上)
目录 上一篇博文 下一篇博文 前置知识 回顾上文 最小3D程序完整代码地址 通用语言 将会在本文解决的不足之处 本文流程 解释本文使用的领域驱动设计的一些概念 本文的领域驱动设计选型 设计 引擎名 识 ...
- 设计模式-12组合模式(Composite Pattern)
1.模式动机 很多时候会存在"部分-整体"的关系,例如:大学中的部门与学院.总公司中的部门与分公司.学习用品中的书与书包.在软件开发中也是这样,例如,文件系统中的文件与文件夹.窗体 ...
- Py基础之函数
'''函数是指一类同类事物的抽象,而且这种抽象可以拓展,并且可以用在同一类事物上'''print (abs(-100),abs(100)) #abs函数是python内置的函数,可以用来求绝对值#pr ...
- Swift --闭包表达式与闭包(汇编分析)
在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数! 一.闭包表达式 概念 闭包表达式与定义函数的语法相对比,有区别如下: 去除了func 去除函数名 返回值类型添加了关键 ...
- 【echarts3】 折线图我踩过的那些坑 (tooltip 设置,line 单个点/散点不显示问题)
echarts 折线图小技巧 echarts 折线图功能丰富且官方文档详细易懂,上手比较容易,这篇文章将分享一些项目中踩过的坑,示例主要以多条曲线为主,对大家完成一些 曲线.tooltip 和 mar ...