多线程Thread,线程池ThreadPool

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

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

一:线程Thread

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

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

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

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

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

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

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

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

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

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

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

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

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

 1 private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
 2 {
 3
 4     ThreadStart method = new ThreadStart(() =>
 5     {
 6         threadStart.Invoke();
 7         actionCallback.Invoke();
 8     });
 9     new Thread(method).Start();
10 }

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

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

 1 private Func<T> ThreadWithReturn<T>(Func<T> func)
 2 {
 3     T t = default(T);
 4     ThreadStart threadStart = new ThreadStart(() =>
 5     {
 6         t = func.Invoke();
 7     });
 8     Thread thread = new Thread(threadStart);
 9     thread.Start();
10
11     return new Func<T>(() =>
12     {
13         thread.Join();
14         //thread.ThreadState
15         return t;
16     });
17 }

二:线程池ThreadPool

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

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

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

1:创建线程池

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

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

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

3:线程池等待

 1 {
 2     ManualResetEvent mre = new ManualResetEvent(true);
 3
 4     ThreadPool.QueueUserWorkItem(o =>
 5     {
 6         this.DoSomethingLong("btnThreadPool_Click1");
 7         // mre.Set();
 8     });
 9
10     Console.WriteLine("over1...");
11     Console.WriteLine("over2...");
12     Console.WriteLine("over3...");
13
14     mre.WaitOne();
15     Console.WriteLine("任务已经完成了。。。");
16 }

注意:

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

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

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

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

 1  {
 2      //最大线程设置为8
 3      ThreadPool.SetMaxThreads(8, 8);
 4      ManualResetEvent mre = new ManualResetEvent(false);
 5      for (int i = 0; i < 10; i++)
 6      {
 7          int k = i;
 8          ThreadPool.QueueUserWorkItem(t =>
 9          {
10              Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} show {k}");
11              if (k == 9)
12              {
13                  //第9次设置打开线程池信号,由于线程池里面一共只有8个线程,然后第9个将不会有多余的线程执行打开信号,则"任务全部执行成功"将不会输出
14                  mre.Set();
15              }
16              else
17              {
18                  mre.WaitOne();
19              }
20          });
21      }
22      if (mre.WaitOne())
23      {
24          Console.WriteLine("任务全部执行成功!");
25      }
26  }

原文地址:https://www.cnblogs.com/loverwangshan/p/10415937.html

时间: 2024-11-08 22:46:37

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

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

在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒                   这一般使用Timer(定时器)来解决: 本篇文章单单讲线程池[ThreadPool] ThreadPool类 MSDN帮助信息: http://msdn.microsoft.com/z

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

上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止,显然是很麻烦的一件事情.还好.net framework为我们提供了线程池ThreadPool来帮助我们来管理这些线程,这样我们就不再需要手动地去终止这些线程.这一篇文章就让我们来学习一下线程池ThreadPool吧.关于它我想从以下几个方面进行总结. 认识线程池ThreadPool Thread

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

在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒                   这一般使用Timer(定时器)来解决: 本篇文章单单讲线程池[ThreadPool] ThreadPool类 MSDN帮助信息: http://msdn.microsoft.com/z

多线程二:线程池(ThreadPool)

在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. 1 private void Threads_Click(object sender, EventArgs e) 2 { 3 Console.WriteLine($"****************btnThreads_Click Start {Thread.CurrentThread.Manage

43_2013年11月22日 线程池 Socket(Thread Lock Process 摇奖 线程池ThreadPool)

1>模拟线程池,生产者消费者问题 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Product { class Program { static void Main(string[] args) { //创建一个池子 MyConncetion[]

C#多线程之线程池篇3

在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关知识. 五.使用等待句柄和超时 在这一小节中,我们将学习如何在线程池中实现超时和正确地实现等待.具体操作步骤如下: 1.使用Visual Studio 2015创建一个新的控制台应用程序. 2.双击打开"Program.cs"文件,编写代码如下所示: 1 using System; 2 u

C#多线程之线程池篇2

在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我们将学习对于大量的异步操作,使用线程池和分别使用单独的线程在性能上有什么差异性.具体操作步骤如下: 1.使用Visual Studio 2015创建一个新的控制台应用程序. 2.双击打开"Program.cs"文件,编写代码如下所示: 1 using System; 2 using Sys

高效线程池(threadpool)的实现

高效线程池(threadpool)的实现 Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程模型的变种,无论其怎么演化,其核心组件都包含了Reactor实例(提供事件注册.注销.通知功能).多路复用器(由操作系统提供,比如kqueue.select.epoll等).事件处理器(负责事件的处理)以及事件源(linux中这就是描述符)这四个组件.一般,会单独启动一个线程运行Reactor实例

多线程及线程池学习心得

一.线程的应用与特点 多线程是程序员不可或缺的技术能力,多线程技术在各个方面都有应用,特别在性能优化上更是起到至关重要的作用.但是,如果多线程写得不好,往往会适得其反,特别是高并发时会造成阻塞.超时等现象.多线程具有以下特点:1.独立性,拥有自己独立的资源,拥有自己私有的地址空间:2.动态性,进程具有自己的生命周期和各种不同的状态:3.并发性,多个进程可以在单个处理器上并发执行,不会相互影响,并行是指同一时刻有多条指令在多个处理器上同时执行.线程是进程的组成部分,一个进程可以拥有多个线程,一个线