C#多线程 线程的启动
在实例化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#多线程 线程的启动的更多相关文章
- Java多线程之线程的启动
Java多线程之线程的启动 一.前言 启动线程的方法有如下两种. 利用Thread 类的子类的实例启动线程 利用Runnable 接口的实现类的实例启动线程 最后再介绍下java.util.concu ...
- C#多线程编程(1):线程的启动
转:http://blog.csdn.net/zhoufoxcn/article/details/4402999 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来 ...
- C++ 11 多线程--线程管理
说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...
- C#多线程--线程池(ThreadPool)
先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...
- Java多线程线程学习(一)
一.操作系统级别的进程与线程1.进程: 一个计算机程序的运行实例.包含了需要执行的指令,有自己的独立地址空间,是互相隔离的.进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理.2.线程: 表 ...
- java 多线程—— 线程让步
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- java 多线程—— 线程等待与唤醒
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程--线程及相关的Java API
Java多线程--线程及相关的Java API 线程与进程 进程是线程的容器,程序是指令.数据的组织形式,进程是程序的实体. 一个进程中可以容纳若干个线程,线程是轻量级的进程,是程序执行的最小单位.我 ...
- java多线程——线程池源码分析(一)
本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...
随机推荐
- 【BZOJ 3445】【Usaco2014 Feb】Roadblock
http://www.lydsy.com/JudgeOnline/problem.php?id=3445 加倍的边一定在最短路上(否则继续走最短路). 最短路长度是O(n)的,暴力扫最短路上的每条边, ...
- [转]Android自定义控件三部曲系列完全解析(动画, 绘图, 自定义View)
来源:http://blog.csdn.net/harvic880925/article/details/50995268 一.自定义控件三部曲之动画篇 1.<自定义控件三部曲之动画篇(一)—— ...
- 用Model-View-ViewModel构建iOS App(转)
转载自 Model-View-ViewModel for iOS [译] 如果你已经开发一段时间的iOS应用,你一定听说过Model-View-Controller, 即MVC.MVC是构建iOS a ...
- BZOJ1303 [CQOI2009]中位数图
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- IIS配置MP3/MP4/OGG/flv等资源文件访问
配置过程参考:http://www.cnblogs.com/EasonJim/p/4752399.html 以下包含了mp4的mime类型: 323 text/h323 acx application ...
- IIS请求筛选模块被配置为拒绝超过请求内容长度的请求
HTTP错误404.13 - Not Found 请求筛选模块被配置为拒绝超过请求内容长度的请求,原因是Web服务器上的请求筛选被配置为拒绝该请求,因为内容长度超过配置的值(IIS 7 默认文件上传大 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
- CATransition的type属性类型
用字符串表示 pageCurl 向上翻一页 pageUnCurl 向下翻一页 rippleEffect 滴水效果 s ...
- ES6箭头函数与展开运算符
箭头函数:省去了关键字function和return: eg: reduce=(a,b)=>a+b;//返回a+b的值 redduce=(a,b)=>{console.log(a);con ...
- Oracle以15分钟为界,统计一天内各时间段的数据笔数
db.table替换为自己的表名,StartTime为date字段 select count(*), (case floor((to_char(StartTime,'mi'))/15) when 0 ...