在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。

不带参数的启动方式

如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace ConsoleApplication_Thread
{
class Program
{
int interval = ;
static void Main(string[] args)
{
Program p = new Program();
Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
//Thread nonParameterThread = new Thread(p.NonParameterRun);
nonParameterThread.Start();
} /// <summary>
/// 不带参数的启动方法
/// </summary>
public void NonParameterRun()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("系统当前时间毫秒值:"+DateTime.Now.Millisecond.ToString());
Thread.Sleep(interval);
}
Console.ReadKey();
}
}
}

程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到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 ConsoleApplication_Thread
{
class Program
{
//int interval = 200;
static void Main(string[] args)
{
Program p = new Program();
Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
parameterThread.Name = "线程1:";//指定当前线程名称
parameterThread.Start();//将值1000传递给子线程委托方法的参数上
} /// <summary>
/// 带参数的启动方法
/// </summary>
/// <param name="ms"></param>
public void ParameterRun(object ms)
{
int j = ;
int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常 for (int i = ; i < ; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
Thread.Sleep(j);
}
Console.ReadLine();
}
}
}

在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:
parameterThread.Start(30);
线程启动时运行的方法是public
void ParameterRun(object
ms),这个值为1000的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。

假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace ConsoleApplication_Thread
{
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();
//启动第二个线程
parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
parameterThread.Name = "Thread B:";
parameterThread.Start();
} /// <summary>
/// 带参数的启动方法
/// </summary>
/// <param name="ms">让线程在运行过程中的休眠间隔</param>
public void ParameterRun(object ms)
{
int j = ;
int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
for (int i = ; i < ; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
Thread.Sleep(j);//让线程暂停
}
Console.ReadKey();
}
}
}

对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在(也就是说实例被销毁了),例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。

继续探索

上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),说白点就是我需要很多的参数,这个问题该如何解决呢?

有两种办法可以解决:

首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。
这里说说重新定义一个实体类来解决的方法,代码如下:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace ConsoleApplication_Thread
{
class Program
{
//int interval = 200;
static void Main(string[] args)
{
Program p = new Program();
Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
parameterThread.Name = "线程 A:";
MyThreadParameter paramter = new MyThreadParameter(, );
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 = ; i < parameter.LoopCount; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
Thread.Sleep(parameter.Interval);//让线程暂停
}
Console.ReadKey();
}
} }
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;
}
}
}

第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。
如实现上面的效果,代码如下:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace ConsoleApplication_Thread
{
class Program
{
static void Main(string[] args)
{
MyThreadParameter parameterThread = new myThreadParameter(, );
parameterThread.Start();
}
} 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 = ; i < loopCount; i++)
{
Console.WriteLine("系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());
Thread.Sleep(interval);//让线程暂停
}
}
}
}

上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。

总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。

C#多线程 线程的启动的更多相关文章

  1. Java多线程之线程的启动

    Java多线程之线程的启动 一.前言 启动线程的方法有如下两种. 利用Thread 类的子类的实例启动线程 利用Runnable 接口的实现类的实例启动线程 最后再介绍下java.util.concu ...

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

    转:http://blog.csdn.net/zhoufoxcn/article/details/4402999 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来 ...

  3. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  4. C#多线程--线程池(ThreadPool)

    先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...

  5. Java多线程线程学习(一)

    一.操作系统级别的进程与线程1.进程: 一个计算机程序的运行实例.包含了需要执行的指令,有自己的独立地址空间,是互相隔离的.进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理.2.线程: 表 ...

  6. java 多线程—— 线程让步

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  7. java 多线程—— 线程等待与唤醒

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  8. Java多线程--线程及相关的Java API

    Java多线程--线程及相关的Java API 线程与进程 进程是线程的容器,程序是指令.数据的组织形式,进程是程序的实体. 一个进程中可以容纳若干个线程,线程是轻量级的进程,是程序执行的最小单位.我 ...

  9. java多线程——线程池源码分析(一)

    本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...

随机推荐

  1. go http.Get请求 http.Post请求 http.PostForm请求 Client 超时设置

    http中有Get/Post/PostForm方法 也可以通过http包中设置client 请求配置 ,然后通过client.Do方法实现请求 下demo中功能都实现,其中有详细说明: package ...

  2. maven webapp栽坑录

    一.需求 如何将一个java web项目传给别人?放到github上.要想放到github上,就要学会git,markdown和maven.像那些jar包是不鼓励传到github上的,应该尽量把源文件 ...

  3. autofac与unity注册类型的几个小区别

    //以下两个注册,在Unity中是默认的 //注册控制器,否则不管接口注入还是属性注入都获取不到服务实例 Builder.RegisterControllers(typeof(MvcApplicati ...

  4. 查看mysql语句运行时间的2种方法

    网站运行很慢的时候,我就特别起知道为什么这么慢,所以我查啊查,数据库绝对是很重要的一部分,里面运行的sql是绝对不能放过的.平时做项目的时候,我也会注意sql语句的书写,写出一些高效的sql来,所以我 ...

  5. 我要成为前端工程师!给 JavaScript 新手的建议与学习资源整理

    来源于:http://blog.miniasp.com/post/2016/02/02/JavaScript-novice-advice-and-learning-resources.aspx 今年有 ...

  6. 配置react native遇到的问题

    折腾了两天终于解决了问题,一开始用模拟器是报如下图的错 然后用真机的时候又报下图的错 这个错误网上有很多解决方法,说是要降级处理,将build.gradle中的1.3.1改成1.2.3,但是改完之后问 ...

  7. XCode8 App上传AppStore更新

    1.在这个网站中https://itunesconnect.apple.com 点击"我的APP" 选取需要更新的app 2.点击加号 版本或平台,填写对应的更新版本 3.配置Xc ...

  8. ERwin创建逻辑模型

    1.逻辑实体添加非主键属性的三种的方式 属性1:在图中直接创建 属性2:在模型导航器中创建 属性3:在属性对话框中创建 2.实体显示选项(Entity Display) Rolename/Attrib ...

  9. my computer

    把08年买的电脑换了,自己买的配件装的,狂拽酷炫叼炸天. 配置清单: CPU :英特尔至强E3-1230 V2 主板 :华硕P8Z77-V LX LX2 机箱 :撒哈拉海盗贼王Z6游戏机箱(白色限量版 ...

  10. JS三大特性

    抽象 在分析三大特性之前我们要先了解什么叫抽象. 定义: 在定义一个类的时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板),这种研究问题的方法就称为抽象 一.封装 定义: ...