多线程之旅(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 进程提供了执行一个程序所需要的所有资源, 一个进程的资源包括虚拟的地址空间, ...
随机推荐
- 用shell脚本新建文件并自动生成头说明信息
目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash #此程序的功能是新建shell文件并自动生成 ...
- windows的各种扩展名详解
Windows系统文件按照不同的格式和用途分很多种类,为便于管理和识别,在对文件命名时,是以扩展名加以区分的,即文件名格式为: 主文件名.扩展名.这样就可以根据文件的扩展名,判定文件的种类,从而知道其 ...
- jquery.qrcode笔记
由于一个坑爹的项目需要生成二维码扫描,后台由于数据库比较麻烦,就只能前端做了,于是乎找到Js生成qrcode的一个库:https://github.com/jeromeetienne/jquery-q ...
- 苹果会放弃iPhone吗?
苹果会放弃iPhone吗?一般来讲,这是一个相当白痴的问题,苹果放弃iPhone的概率比唐僧放弃取经的概率要低20倍.前段时间回老家,正在学习英语的小侄子问我:"叔叔,苹果用英语怎么说呀? ...
- 探索Linux通用SCSI驱动器
通过 SCSI 命令管理计算机上的数据,并将数据传输到 SCSI 设备.在本文中,作者介绍了一些 SCSI 命令,以及在 Linux® 中使用 SCSI API 时执行 SCSI 命令的方法.他介绍了 ...
- C++走向远洋——35(友元,时间)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:time.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- GitLab-CI部署及踩坑总结
转载请注明出处:https://www.cnblogs.com/shining5/p/8863063.html 部署GitLab-CI 简介 GitLab_CI(gitlab continuous i ...
- 从头认识js-函数表达式
定义函数的方式有两种: 1.函数声明(特征:函数声明提升,在执行代码之前会先读取函数声明,这就意味着可以把函数声明放在调用它的语句之后) 2.函数表达式(函数表达式与其他表达式一样,使用之前必须先声明 ...
- 动手搞一个Promise
Javascript语言的执行环境是"单线程"(single thread).所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个任 ...
- 【MySQL】:事务四大特性与隔离级别
目录 一.事务的概念 二.事务的四大特性 1.原子性 2.一致性 3.隔离性 4.持续性 三.事务语句 1.开启事务:start transaction 2.事务回滚:rollback 指定回滚点 3 ...