C# 多线程编程 ThreadStart ParameterizedThreadStart
- 原文地址:http://club.topsage.com/thread-657023-1-1.html
- 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。
- 不带参数的启动方式
- 如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Text;
- 4 using System.Threading;
- 5
- 6 namespace StartThread
- 7 {
- 8 class Program
- 9 {
- 10 int interval = 200;
- 11 static void Main(string[] args)
- 12 {
- 13 Program p = new Program();
- 14 Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
- 15 nonParameterThread.Start();
- 16 }
- 17 ///<summary>
- 18 /// 不带参数的启动方法
- 19 ///</summary>
- 20 public void NonParameterRun()
- 21 {
- 22 for (int i = 0; i < 10; i++)
- 23 {
- 24 Console.WriteLine("系统当前时间毫秒值:"+DateTime.Now.Millisecond.ToString());
- 25 Thread.Sleep(interval);//让线程暂停
- 26 }
- 27 }
- 28 }
- 程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到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类型参数时,必须在 启动方法中进行相应的类型转换。
- 下面就是一个例子,在启动线程时指定了线程的暂停间隔,代码如下:
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Text;
- 4 using System.Threading;
- 5
- 6 namespace StartThread
- 7 {
- 8 class Program
- 9 {
- 10 int interval = 200;
- 11 static void Main(string[] args)
- 12 {
- 13 Program p = new Program();
- 14
- 15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- 16 parameterThread.Name = "Thread A:";
- 17 parameterThread.Start(30);
- 18 }
- 19
- 20 ///<summary>
- 21 /// 带参数的启动方法
- 22 ///</summary>
- 23 ///<param name="ms">让线程在运行过程中的休眠间隔</param>
- 24 public void ParameterRun(object ms)
- 25 {
- 26 int j = 10;
- 27 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
- 28 for (int i = 0; i < 10; i++)
- 29 {
- 30 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
- 31 Thread.Sleep(j);//让线程暂停
- 32 }
- 33 }
- 34 }
- 35 }
- 在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:
- parameterThread.Start(30);
- 线程启动时运行的方法是public void ParameterRun(object ms),这个值为30的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。
- 假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Text;
- 4 using System.Threading;
- 5
- 6 namespace StartThread
- 7 {
- 8 class Program
- 9 {
- 10 int interval = 200;
- 11 static void Main(string[] args)
- 12 {
- 13 Program p = new Program();
- 14
- 15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- 16 parameterThread.Name = "Thread A:";
- 17 parameterThread.Start(30);
- 18 //启动第二个线程
- 19 parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- 20 parameterThread.Name = "Thread B:";
- 21 parameterThread.Start(60);
- 22 }
- 23
- 24 ///<summary>
- 25 /// 带参数的启动方法
- 26 ///</summary>
- 27 ///<param name="ms">让线程在运行过程中的休眠间隔</param>
- 28 public void ParameterRun(object ms)
- 29 {
- 30 int j = 10;
- 31 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
- 32 for (int i = 0; i < 10; i++)
- 33 {
- 34 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
- 35 Thread.Sleep(j);//让线程暂停
- 36 }
- 37 }
- 38 }
- 39 }
- 对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在,例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。
- 继续探索
- 上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),这个问题该如何解决呢?
- 有两种办法可以解决:
- 首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。
- 这里说说重新定义一个实体类来解决的方法,代码如下。
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Text;
- 4 using System.Threading;
- 5
- 6 namespace StartThread
- 7 {
- 8 class MyThreadParameter
- 9 {
- 10 private int interval;
- 11 private int loopCount;
- 12 ///<summary>
- 13 /// 循环次数
- 14 ///</summary>
- 15 public int LoopCount
- 16 {
- 17 get { return loopCount; }
- 18 }
- 19
- 20 ///<summary>
- 21 /// 线程的暂停间隔
- 22 ///</summary>
- 23 public int Interval
- 24 {
- 25 get { return interval; }
- 26 }
- 27 ///<summary>
- 28 /// 构造函数
- 29 ///</summary>
- 30 ///<param name="interval">线程的暂停间隔</param>
- 31 ///<param name="loopCount">循环次数</param>
- 32 public MyThreadParameter(int interval,int loopCount)
- 33 {
- 34 this.interval = interval;
- 35 this.loopCount = loopCount;
- 36 }
- 37 }
- 38 class Program
- 39 {
- 40 int interval = 200;
- 41 static void Main(string[] args)
- 42 {
- 43 Program p = new Program();
- 44
- 45 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
- 46 parameterThread.Name = "Thread A:";
- 47 MyThreadParameter paramter = new MyThreadParameter(50, 20);
- 48 parameterThread.Start(paramter);
- 49 }
- 50
- 51
- 52 ///<summary>
- 53 /// 带多个参数的启动方法
- 54 ///</summary>
- 55 ///<param name="ms">方法参数</param>
- 56 public void MyParameterRun(object ms)
- 57 {
- 58 MyThreadParameter parameter = ms as MyThreadParameter;//类型转换
- 59 if (parameter != null)
- 60 {
- 61 for (int i = 0; i < parameter.LoopCount; i++)
- 62 {
- 63 Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
- 64 Thread.Sleep(parameter.Interval);//让线程暂停
- 65 }
- 66 }
- 67 }
- 68 }
- 69 }
- 第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。
- 如果实现上面的效果,代码如下:
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Text;
- 4 using System.Threading;
- 5
- 6 namespace StartThread
- 7 {
- 8 class MyThreadParameter
- 9 {
- 10 private int interval;
- 11 private int loopCount;
- 12 private Thread thread;
- 13
- 14 ///<summary>
- 15 /// 构造函数
- 16 ///</summary>
- 17 ///<param name="interval">线程的暂停间隔</param>
- 18 ///<param name="loopCount">循环次数</param>
- 19 public MyThreadParameter(int interval,int loopCount)
- 20 {
- 21 this.interval = interval;
- 22 this.loopCount = loopCount;
- 23 thread = new Thread(new ThreadStart(Run));
- 24 }
- 25
- 26 public void Start()
- 27 {
- 28 if (thread != null)
- 29 {
- 30 thread.Start();
- 31 }
- 32 }
- 33
- 34 private void Run()
- 35 {
- 36 for (int i = 0; i < loopCount; i++)
- 37 {
- 38 Console.WriteLine("系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
- 39 Thread.Sleep(interval);//让线程暂停
- 40 }
- 41 }
- 42 }
- 43 class Program
- 44 {
- 45 static void Main(string[] args)
- 46 {
- 47 MyThreadParameter parameterThread = new MyThreadParameter(30, 50);
- 48 parameterThread.Start();
- 49 }
- 50
- 51 }
- 52 }
- 上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。
- 总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。
C# 多线程编程 ThreadStart ParameterizedThreadStart的更多相关文章
- 多线程之 ThreadStart 和 ParameterizedThreadStart 委托
先看微软如何给出的方法使用,如下查看,我们发现,如下两个委托,分别对应带参数创建线程 和 不带参数创建线程. 下列 委托 方法不带参数 ThreadStart namespace System.Thr ...
- 浅述WinForm多线程编程与Control.Invoke的应用
VS2008.C#3.0在WinForm开发中,我们通常不希望当窗体上点了某个按钮执行某个业务的时候,窗体就被卡死了,直到该业务执行完毕后才缓过来.一个最直接的方法便是使用多线程.多线程编程的方式在W ...
- C#多线程编程总结
VS2008.C#3.0在WinForm开发中,我们通常不希望当窗体上点了某个按钮执行某个业务的时候,窗体就被卡死了,直到该业务执行完毕后才缓过来.一个最直接的方法便是使用多线程.多线程编程的方式在W ...
- C#多线程编程笔记
在开发中经常有遇到因为程序执行的时间过长,而造成程序假死的情况,这是因为我们的程序是同步执行的,当执行到需要长时间的操作时,程序就会等待当前的操作完成,从而造成程序假死.C#的异步与多线程就是为了解决 ...
- C#多线程编程实战(二)
1.1 简介 为了防止一个应用程序控制CPU而导致其他应用程序和操作系统本身永远被挂起这一可能情况,操作系统不得不使用某种方式将物理计算分割为一些虚拟的进程,并给予每个执行程序一定量的计算能力.此外操 ...
- C# 多线程编程,传参,接受返回值
C# 多线程编程,传参,接受返回值 今天将多线程的知识有回顾了下,总结了几点: 新建一个线程(无参数,无返回值) Thread th = new Thread(new ThreadStart(Prin ...
- WinForm多线程编程与Control.Invoke的应用浅谈
在WinForm开发中,我们通常不希望当窗体上点了某个按钮执行某个业务的时候,窗体就被卡死了,直到该业务执行完毕后才缓过来.一个最直接的方法便是使用多线程.多线程编程的方式在WinForm开发中必不可 ...
- C# 多线程编程第一步——理解多线程
一.进程.线程及多线程的概念 什么是多线程呢?不理解. 那什么是线程呢?说到线程就不得不说说进程.我在网上搜索也搜索了一些资料,大部分所说的进程其实是很抽象的东西.通俗的来讲,进程就是一个应用程序开始 ...
- 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)
数据结构(逻辑结构,物理结构,特点) 一.数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关.逻辑结构包括: 集合 数 ...
随机推荐
- Jump Game —— LeetCode
Given an array of non-negative integers, you are initially positioned at the first index of the arra ...
- vtk 导出结果图片
项目中需要将渲染结果导出为图片. (1) 一开始搜了vtk的方法,发现: http://blog.csdn.net/lbluekey/article/details/3346312 http://w ...
- HDOJ 2027 统计元音
Problem Description 统计每个元音字母在字符串中出现的次数. Input 输入数据首先包括一个整数n,表示测试实例的个数,然后是n行长度不超过100的字符串. Output 对于每个 ...
- POJ 3208 Apocalypse Someday
题意: 将含有连续的三个6的数称为不吉利数,比如666,1666,6662,但是6266吉利.则666为第一个不吉利数,输入整数n,求第n个不吉利数.(n <= 5*10^7) 解法: 如果是给 ...
- 终止imp/exp和expdp/impdp进程运行的方法
一.停止EXP/IMP优化速度 可以直接KILL 进程,但先要KILL 父进程,然后KILL子进程,只KILL子进程,EXP/IMP还会在后台执行的 样例:ps -ef |grep imp 查询到pi ...
- Android自定义Toast宽度无法设置问题解决
在项目中想要实现一个头部的toast提示效果,类似下图 再实现的过程中发现,如果直接通过修改Toast的View布局的父控件宽度是无法实现效果的,后来是通过直接用代码指定父控件内部的textview ...
- RHEL6.4编译安装gcc4.8.1
因为平时用的linux虚拟机都是RHEL6.4, 自带的gcc版本号太低,不支持C++11,而从gcc4.8.1開始, gcc完美支持C++11全部特性. 故升级了一下. 以下是具体步骤: 1. 下载 ...
- Hadoop与HBase中遇到的问题
1. Hadoop中遇到的问题 曾经所遇到的问题因为没有记录,所以忘了 (1)NameNode没有启动成功, 是因为你对HDFS多次格式化,导致datanode中与namenode中的VERSION文 ...
- 计数dp-hdu-4054-Number String
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4055 题目大意: 给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D ...
- Android(java)学习笔记227:服务(service)之服务的生命周期 与 两种启动服务的区别
1.之前我们在Android(java)学习笔记171:Service生命周期 (2015-08-18 10:56)说明过,可以回头看看: 2.Service 的两种启动方法和区别: (1)Servi ...