C#多线程编程(1):线程的启动

简介:
 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。
 不带参数的启动方式
 如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:
 
using System; 
  using System.Collections.Generic; 
  using System.Text; 
  using System.Threading; 
    
  namespace StartThread 
 { 
          class Program 
         { 
                  int interval = 200; 
                  static  void Main( string[] args) 
                 { 
                         Program p =  new Program(); 
                         Thread nonParameterThread =  new Thread( new ThreadStart(p.NonParameterRun)); 
                         nonParameterThread.Start(); 
                 } 
                  /// <summary> 
                  /// 不带参数的启动方法 
                  /// </summary> 
                  public  void NonParameterRun() 
                 { 
                          for ( int i = 0; i < 10; i++) 
                         { 
                                 Console.WriteLine( "系统当前时间毫秒值:"+DateTime.Now.Millisecond.ToString()); 
                                 Thread.Sleep(interval); //让线程暂停 
                         } 
         } 
 }

 程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到10次之后运行完毕,终止线程的执行。
 在上面的代码中我们是通过定义全局变量的方法来指定线程暂停间隔,按照这种方法,假如要运行10个线程,每个线程的暂停间隔不一样的话,就需要定义10个全局变量,虽然最终不影响系统的运行效果,但是总觉得不是太爽。
 有没有比较简单一点的办法呢?有!那就是使用带参数的启动方法。
  带参数的启动方法
 如果要在实例化线程时要带一些参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要ParameterizedThreadStart委托,和ThreadStart一样的是它也是线程启动时要执行的方法,和ThreadStart不同的是,它在实例化时可以用一个带有一个Object参数的方法作为构造函数的参数,而实例化ThreadStart时所用到的方法是没有参数的。
 为什么是Object这样的参数呢?很简单,因为在.net中Object是所有类型的基类,用它可以表示Array(数组)、Interface(接口)、ValueType(值类型,如bool,byte,char,short,int,float,long,double等)、class(类)等.net中的类型。当然,这也意味着如果你要启动一个线程,给它传递一个int类型参数时,必须在启动方法中进行相应的类型转换。
 下面就是一个例子,在启动线程时指定了线程的暂停间隔,代码如下:
 
using System; 
  using System.Collections.Generic; 
  using System.Text; 
  using System.Threading; 
    
  namespace StartThread 
 { 
          class Program 
         { 
                  int interval = 200; 
                  static  void Main( string[] args) 
                 { 
                         Program p =  new Program(); 
    
                         Thread parameterThread =  new Thread( new ParameterizedThreadStart(p.ParameterRun)); 
                         parameterThread.Name =  "Thread A:"
                         parameterThread.Start(30); 
                 } 
         
                  /// <summary> 
                  /// 带参数的启动方法 
                  /// </summary> 
                  /// <param name="ms">让线程在运行过程中的休眠间隔</param> 
                  public  void ParameterRun( object ms) 
                 { 
                          int j = 10; 
                          int.TryParse(ms.ToString(),  out j); //这里采用了TryParse方法,避免不能转换时出现异常 
                          for ( int i = 0; i < 10; i++) 
                         { 
                                 Console.WriteLine(Thread.CurrentThread.Name+ "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 
                                 Thread.Sleep(j); //让线程暂停 
                         } 
                 } 
         } 
 }

 在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:
 parameterThread.Start(30);
 线程启动时运行的方法是public void ParameterRun(object ms),这个值为30的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。
 假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:
using System; 
  using System.Collections.Generic; 
  using System.Text; 
  using System.Threading; 
    
  namespace StartThread 
 { 
          class Program 
         { 
                  int interval = 200; 
                  static  void Main( string[] args) 
                 { 
                         Program p =  new Program(); 
    
                         Thread parameterThread =  new Thread( new ParameterizedThreadStart(p.ParameterRun)); 
                         parameterThread.Name =  "Thread A:"
                         parameterThread.Start(30); 
                          //启动第二个线程 
                         parameterThread =  new Thread( new ParameterizedThreadStart(p.ParameterRun)); 
                         parameterThread.Name =  "Thread B:"
                         parameterThread.Start(60); 
                 } 
         
                  /// <summary> 
                  /// 带参数的启动方法 
                  /// </summary> 
                  /// <param name="ms">让线程在运行过程中的休眠间隔</param> 
                  public  void ParameterRun( object ms) 
                 { 
                          int j = 10; 
                          int.TryParse(ms.ToString(),  out j); //这里采用了TryParse方法,避免不能转换时出现异常 
                          for ( int i = 0; i < 10; i++) 
                         { 
                                 Console.WriteLine(Thread.CurrentThread.Name+ "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 
                                 Thread.Sleep(j); //让线程暂停 
                         } 
                 } 
         } 
 }

  对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在,例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。
 
  继续探索
 上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),这个问题该如何解决呢?
 有两种办法可以解决:
 首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。
 这里说说重新定义一个实体类来解决的方法,代码如下。
 
using System; 
  using System.Collections.Generic; 
  using System.Text; 
  using System.Threading; 
    
  namespace StartThread 
 { 
          class MyThreadParameter 
         { 
                  private  int interval; 
                  private  int loopCount; 
                  /// <summary> 
                  /// 循环次数 
                  /// </summary> 
                  public  int LoopCount 
                 { 
                         get {  return loopCount; } 
                 } 
     
                  /// <summary> 
                  /// 线程的暂停间隔 
                  /// </summary> 
                  public  int Interval 
                 { 
                         get {  return interval; } 
                 } 
             /// <summary> 
             /// 构造函数 
             /// </summary> 
                  /// <param name="interval">线程的暂停间隔</param> 
                  /// <param name="loopCount">循环次数</param> 
                  public MyThreadParameter( int interval, int loopCount) 
                 { 
                          this.interval = interval; 
                          this.loopCount = loopCount; 
                 } 
         } 
          class Program 
         { 
                  int interval = 200; 
                  static  void Main( string[] args) 
                 { 
                         Program p =  new Program(); 
    
                         Thread parameterThread =  new Thread( new ParameterizedThreadStart(p.MyParameterRun)); 
                         parameterThread.Name =  "Thread A:"
                         MyThreadParameter paramter =  new MyThreadParameter(50, 20); 
                         parameterThread.Start(paramter); 
                 } 
     
    
                  /// <summary> 
                  /// 带多个参数的启动方法 
                  /// </summary> 
                  /// <param name="ms">方法参数</param> 
                  public  void MyParameterRun( object ms) 
                 { 
                         MyThreadParameter parameter = ms  as MyThreadParameter; //类型转换 
                          if (parameter !=  null
                         { 
                                  for ( int i = 0; i < parameter.LoopCount; i++) 
                                 { 
                                         Console.WriteLine(Thread.CurrentThread.Name +  "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 
                                         Thread.Sleep(parameter.Interval); //让线程暂停 
                                 } 
                         } 
                 } 
         } 
 }
 第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。
 如果实现上面的效果,代码如下:
 
using System; 
  using System.Collections.Generic; 
  using System.Text; 
  using System.Threading; 
    
  namespace StartThread 
 { 
          class MyThreadParameter 
         { 
                  private  int interval; 
                  private  int loopCount; 
                  private Thread thread; 
                    
     /// <summary> 
     /// 构造函数 
     /// </summary> 
                  /// <param name="interval">线程的暂停间隔</param> 
                  /// <param name="loopCount">循环次数</param> 
                  public MyThreadParameter( int interval, int loopCount) 
                 { 
                          this.interval = interval; 
                          this.loopCount = loopCount; 
                         thread =  new Thread( new ThreadStart(Run)); 
                 } 
    
                  public  void Start() 
                 { 
                          if (thread !=  null
                         { 
                                 thread.Start(); 
                         } 
                 } 
    
                  private  void Run() 
                 { 
                          for ( int i = 0; i < loopCount; i++) 
                         { 
                                 Console.WriteLine( "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 
                                 Thread.Sleep(interval); //让线程暂停 
                         } 
                 } 
         } 
          class Program 
         { 
                  static  void Main( string[] args) 
                 { 
                         MyThreadParameter parameterThread =  new MyThreadParameter(30, 50); 
                         parameterThread.Start(); 
                 } 
    
         } 
 }

 上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。
 
 总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。
















本文转自周金桥51CTO博客,原文链接:http://blog.51cto.com/zhoufoxcn/187031  ,如需转载请自行联系原作者


相关文章
|
2月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
184 6
|
5月前
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
320 83
|
5月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
248 0
|
3月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
241 19
|
2月前
|
Java 调度 数据库
Python threading模块:多线程编程的实战指南
本文深入讲解Python多线程编程,涵盖threading模块的核心用法:线程创建、生命周期、同步机制(锁、信号量、条件变量)、线程通信(队列)、守护线程与线程池应用。结合实战案例,如多线程下载器,帮助开发者提升程序并发性能,适用于I/O密集型任务处理。
322 0
|
3月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
289 16
|
4月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
752 0
|
5月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
6月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
434 5
|
6月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
205 0