首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到

  #region Private Method
/// <summary>
/// 一个比较耗时耗资源的私有方法
/// </summary>
/// <param name="name"></param>
private void DoSomethingLong(string name)
{
Console.WriteLine($"*****DoSomethingLong开始;参数【{name}】;线程Id:【{Thread.CurrentThread.ManagedThreadId.ToString("")}】;当前时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***");
long result = ;
for (int i = ; i < 1_000_000_000; i++)
{
result += i;
}
Console.WriteLine($"*****DoSomethingLong结束;参数【{name}】;线程Id:【{Thread.CurrentThread.ManagedThreadId.ToString("")}】;当前时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")};result:{result}***");
}
#endregion

一:线程Thread

Thread类是C#语言对线程对象的一个封装,是.netFramwork1.0的出现的

我们先介绍一下Thread的一些常用方法

1:线程启动的两种方法如下:

 {
//一:启动带参数的线程 ParameterizedThreadStart是一个带object的委托,可以传任何类型
ParameterizedThreadStart method = o => this.DoSomethingLong(o.ToString());
Thread thread = new Thread(method);
thread.Start("");//开启线程,执行委托的内容
}
{
//二:启动无参的线程
ThreadStart method = () =>
{
Thread.Sleep();
this.DoSomethingLong("测试");
Thread.Sleep();
};
Thread thread = new Thread(method);
thread.Start();//开启线程,执行委托的内容
}

2:等待线程完成有两种方法如下:

  {
ThreadStart method = () =>
{
Thread.Sleep();
this.DoSomethingLong("测试");
Thread.Sleep();
};
Thread thread = new Thread(method);
thread.Start();//开启线程,执行委托的内容 //1:使用线程的ThreadState状态来判断等待
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep();//当前线程休息200ms
} // 2: Join等待
thread.Join();//运行这句代码的线程,等待thread的完成
thread.Join();//最多等待1000ms
}
ThreadState这个是一个枚举,主要是判断线程的状态,具体参考下图:

3:线程的一些其它方法介绍,具体看代码注释

  {
ThreadStart method = () =>
{
Thread.Sleep(); //休息5000毫秒,这个用的比较多
this.DoSomethingLong("测试");
Thread.Sleep();
};
Thread thread = new Thread(method);
thread.Start();//开启线程,执行委托的内容 //以下方法是线程自带的方法,但是线程是调度操作系统资源的,所以如果对线程胡乱更改,会造成线程混乱,以下方法都不建议使用
thread.Suspend();//暂停;方法已过时,不建议使用
thread.Resume();//恢复;方法已过时,不建议使用
thread.Abort(); //终止线程;线程是计算机资源,程序想停下线程,只能向操作系统通知(线程抛异常),会有延时/不一定能真的停下来
Thread.ResetAbort(); //取消终止线程
}

4:线程的一些属性介绍,具体看代码注释:

 {
ThreadStart method = () =>
{
Thread.Sleep();
this.DoSomethingLong("测试");
Thread.Sleep();
};
Thread thread = new Thread(method);
thread.Start();//开启线程,执行委托的内容 //最高优先级:优先执行,但不代表优先完成 甚至说极端情况下,还有意外发生,不能通过这个来控制线程的执行先后顺序
thread.Priority = ThreadPriority.Highest; thread.IsBackground = false;//默认是false 前台线程,进程关闭,线程需要计算完后才退出
//thread.IsBackground = true;//设置为后台线程,关闭进程,线程退出
ThreadState threadState = thread.ThreadState; //当前线程的状态,具体如上面的一截图
string name = thread.Name;//进程的名字
int threadId= Thread.CurrentThread.ManagedThreadId; //线程的Id
}

5:之前的异步方法我们都想控制先后顺序,比如:启动子线程执行动作A--不阻塞--A执行完后子线程会执行动作B,然而线程我们也想实现这样的功能,这时候大部分人都会想先等线程执行完,然后再执行下面的方法,如下:

    private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
{
Thread thread = new Thread(threadStart);
thread.Start();
thread.Join();//错了,因为方法被阻塞了
actionCallback.Invoke();
}

其实这些都是都会把异步变成了同步了,然后启动线程就没有太多意义了,我们可以修改为如下:

 private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
{ ThreadStart method = new ThreadStart(() =>
{
threadStart.Invoke();
actionCallback.Invoke();
});
new Thread(method).Start();
}

其实我们上面做的仅仅是把两个有先后顺序的同步方法放在一个异步线程中即可

6:以下方法我们既能实现异步非堵塞,又能获取到最终的计算结果

 private Func<T> ThreadWithReturn<T>(Func<T> func)
{
T t = default(T);
ThreadStart threadStart = new ThreadStart(() =>
{
t = func.Invoke();
});
Thread thread = new Thread(threadStart);
thread.Start(); return new Func<T>(() =>
{
thread.Join();
//thread.ThreadState
return t;
});
}

二:线程池ThreadPool

线程池.NetFramework2.0,如果某个对象创建和销毁代价比较高,同时这个对象还可以反复使用的,就需要一个池子,保存多个这样的对象,需要用的时候从池子里面获取;用完之后不用销毁,放回池子,这些都是线程池自动控制的,编程时候无需要特别关注这些,

ThreadPool的线程都是后台线程(是不是后台线程下面详细介绍),这样做主要是:

  • 节约资源提升性能
  • 还能管控总数量,防止滥用

1:创建线程池

  ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click1"));
ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click2"), "wss");

2:线程池的一些方法属性设置,具体详情如下:

  {
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Console.WriteLine($"当前电脑最大workerThreads={workerThreads} 最大异步I/O 线程的最大数目={completionPortThreads}"); ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);
Console.WriteLine($"当前电脑最小workerThreads={workerThreadsMin} 最大completionPortThreads={completionPortThreadsMin}"); //设置的线程池数量是进程全局的,
//委托异步调用--Task/Parrallel/async/await 全部都是线程池的线程
//直接new Thread不受这个数量限制的(但是会占用线程池的线程数量)
ThreadPool.SetMaxThreads(, );//设置的最大值,必须大于CPU核数,否则设置无效
ThreadPool.SetMinThreads(, );
Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&设置最大最小&&&&&&&&&&&&&&&&&&&&&&&&&&&"); ThreadPool.GetMaxThreads(out int workerThreads1, out int completionPortThreads1);
Console.WriteLine($"当前电脑最大workerThreads={workerThreads1} 最大completionPortThreads={completionPortThreads1}"); ThreadPool.GetMinThreads(out int workerThreadsMin1, out int completionPortThreadsMin1);
Console.WriteLine($"当前电脑最大workerThreads={workerThreadsMin1} 最大completionPortThreads={completionPortThreadsMin1}");
}

3:线程池等待

 {
ManualResetEvent mre = new ManualResetEvent(true); ThreadPool.QueueUserWorkItem(o =>
{
this.DoSomethingLong("btnThreadPool_Click1");
// mre.Set();
}); Console.WriteLine("over1...");
Console.WriteLine("over2...");
Console.WriteLine("over3..."); mre.WaitOne();
Console.WriteLine("任务已经完成了。。。");
}

注意:

mre.Set():设置为有信号
初始值为false即为关闭

  • 只有mre.Set()设置为true为打开信号---WaitOne就才能通过,即waitOne()下面的代码才会执行
  • 如果不进行mre.Set(),则WaitOne就只能等待,下面的代码将不会执行

初始值为true为打开则不需要调用mre.Set() ,waitOne()下面的代码就会直接执行

4:上面我们提到了线程池的最大最小线程数,这个如果线程池中的线程被占用完,则程序将出现将死状态,下面的操作也不执行,也不做任何提示,虽然这是一种极端状态,但是会出现,下面的代码都会出现这种状态

  {
//最大线程设置为8
ThreadPool.SetMaxThreads(, );
ManualResetEvent mre = new ManualResetEvent(false);
for (int i = ; i < ; i++)
{
int k = i;
ThreadPool.QueueUserWorkItem(t =>
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("")} show {k}");
if (k == )
{
//第9次设置打开线程池信号,由于线程池里面一共只有8个线程,然后第9个将不会有多余的线程执行打开信号,则"任务全部执行成功"将不会输出
mre.Set();
}
else
{
mre.WaitOne();
}
});
}
if (mre.WaitOne())
{
Console.WriteLine("任务全部执行成功!");
}
}

多线程Thread,线程池ThreadPool的更多相关文章

  1. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  2. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  3. C# -- 使用线程池 ThreadPool 执行多线程任务

    C# -- 使用线程池 ThreadPool 执行多线程任务 1. 使用线程池 class Program { static void Main(string[] args) { WaitCallba ...

  4. 多线程系列(2)线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  5. C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  6. [转]C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  7. python中多进程multiprocessing、多线程threading、线程池threadpool

    浅显点理解:进程就是一个程序,里面的线程就是用来干活的,,,进程大,线程小 一.多线程threading 简单的单线程和多线程运行:一个参数时,后面要加逗号 步骤:for循环,相当于多个线程——t=t ...

  8. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  9. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

随机推荐

  1. lvm快照备份数据库(Mysql5.7)

    备份的目的 能够防止由于机械故障以及人为误操作带来的数据丢失,例如将数据库文件保存在了其它地方. 备份的分类 以操作过程中服务的可用性分: 冷备份:cold backup mysql服务关闭,mysq ...

  2. 算法与数据结构(四) 图的物理存储结构与深搜、广搜(Swift版)

    开门见山,本篇博客就介绍图相关的东西.图其实就是树结构的升级版.上篇博客我们聊了树的一种,在后边的博客中我们还会介绍其他类型的树,比如红黑树,B树等等,以及这些树结构的应用.本篇博客我们就讲图的存储结 ...

  3. eclipse集成lombok

    第一部下载 lombok jar包 https://projectlombok.org/download.html lombok下载地址,进入该网址后可以看到如下界面,点击下载就行了.   下载 ja ...

  4. 用Vue2仿京东省市区三级联动效果

    三级联动,随着越来越多的审美,出现了很多种,好多公司都仿着淘宝的三级联动 ,好看时尚,so我们公司也一样……为了贴代码方便,我把写在data里面省市区的json独立了出来,下载贴进去即可用,链接如下 ...

  5. emWin表盘界面设计,含uCOS-III和FreeRTOS两个版本

    第4期:简易表盘界面设计 配套例子:V6-906_STemWin提高篇实验_简易表盘界面设计(uCOS-III)V6-907_STemWin提高篇实验_简易表盘界面设计(FreeRTOS) 例程下载地 ...

  6. Python 远程开机

    用 Python 关机你肯定听过或者实践过,那么用 Python 开机呢?这是一个神奇的方法,教你如何用 Python 来开机. 本文目标 远程开机原理 Python 远程开机代码实现 Python ...

  7. git克隆项目出现remote: HTTP Basic: Access denied

    换新电脑,重新装了git,从gitlab上面拉公司项目,出现了remote: HTTP Basic: Access denied错误,说验证失败,百度很多说了很多答案,最后试了这种可以,成功拉下来项目 ...

  8. 写给大忙人的centos下ftp服务器搭建(以及启动失败/XFTP客户端一直提示“用户身份验证失败”解决方法)

    注:个人对偏向于底层基本上拿来就用的应用,倾向于使用安装包,直接yum或者rpm安装:而对于应用层面控制较多或者需要大范围维护的,倾向于直接使用tar.gz版本. 对于linux下的ftp服务器,实际 ...

  9. [Java]LeetCode133. 克隆图 | Clone Graph

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

  10. CDN边缘节点容器调度实践(下)

    5月27日,OSC 源创会在上海成功举办.又拍云系统开发高级工程师黄励博在大会分享了<CDN 边缘节点容器调度的实践>.主要介绍又拍云自主开发的边缘节点容器调度方案,从 0 到 1 ,实现 ...