在实例化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. tensorflow 一些好的blog链接和tensorflow gpu版本安装

    pading :SAME,VALID 区别  http://blog.csdn.net/mao_xiao_feng/article/details/53444333 tensorflow实现的各种算法 ...

  2. asp.net mvc4 简单的服务器监控开发之C#获取服务器CPU、RAM、TCP等系统信息(上)

    一.背景 前段时间服务器出了点问题,加上学业愈来愈紧张,写博文分享的时间越来越少.虽然不是第一次在博客园上写经验,但是近期分享的博文得到了不少的朋友支持和指正,在这里内心非常感激和开心.希望以后能认真 ...

  3. How to Disable Strict SQL Mode in MySQL 5.7

    If your app was written for older versions of MySQL and is not compatible with strict SQL mode in My ...

  4. [信安Presentation]一种基于GPU并行计算的MD5密码解密方法

    -------------------paper--------------------- 一种基于GPU并行计算的MD5密码解密方法 0.abstract1.md5算法概述2.md5安全性分析3.基 ...

  5. MySQL的InnoDB索引原理详解

    摘要 本篇介绍下Mysql的InnoDB索引相关知识,从各种树到索引原理到存储的细节. InnoDB是Mysql的默认存储引擎(Mysql5.5.5之前是MyISAM,文档).本着高效学习的目的,本篇 ...

  6. Servlet使用注解标注监听器(Listener)

    Servlet3.0提供@WebListener注解将一个实现了特定监听器接口的类定义为监听器,这样我们在web应用中使用监听器时,也不再需要在web.xml文件中配置监听器的相关描述信息了. 下面我 ...

  7. 记一次特别的bug

    问题现象 push入某个特定的画页,然后再pop出来,然后再切换不同的tabbaritem就会崩溃,而且没有任何提示,也没法定位崩溃位置,哪怕用了$arg1. 猜测,这种情况坏访问的可能性比较大,至少 ...

  8. [Java] Maven 建立 Spring MVC 工程

    GIT: https://github.com/yangyxd/Maven.SpringMVC.Web 1. 建立 WebApp 工程 下一步: 下一步: 选择 maven-archetype-web ...

  9. mysql二级索引

    以InnoDB来说,每个InnoDB表具有一个特殊的索引称为聚集索引.如果您的表上定义有主键,该主键索引是聚集索引.如果你不定义为您的表的主键 时,MySQL取第一个唯一索引(unique)而且只含非 ...

  10. TeamViewer 12.0.71503 Patch By.Sound

    TeamViewer - the All-In-One Software for Remote Support and Online Meetings - Remote control any com ...