多线程系列(1):初识多线程

 

 

 

作为.NET或JAVA程序员,多线程编程似乎是我们不可避免的,当初JAVA刚出世时就大打招牌称其支持多线程,.NET出道时也不忘着重申明其多线程特性。那么我们现在开始一起从0接触多线程。
1 基本概念
程序:指令的集合,它是一个静态的实体,没有执行的含义,自然也就没有生命周期。程序在运行的时候会产生进程(不运行自然就没有),所以说一个程序有0个、1个或多个进程组成。
进程:做为程序的一部分,它是一个动态的实体,有完整的生命周期。进程是资源分配和拥有的基本单位,同一个进程内的线程共享进程的资源。
线程:它是进程内的一个执行单元,是处理器调度的基本单位,进程至少有一个线程。和进程一样,线程也具有并发性。
多线程:上面说到,一个进程至少有一个线程,那么当一个进程有多个线程时,我们称之为多线程。它的实际意义是指一个程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并发执行的线程来完成各自的任务。
2 为什么要用多线程
首先说明一点,线程间的切换是需要时间的,既然这样,那么你开辟的线程越多,不就是浪费的时间越多吗?为何还要用多线程呢?实际不然,因为CPU经常是处于空闲状态地等待状态,而在此状态,我们可以让CPU执行其他的线程,这样可以大大提高程序的效率。
 但是,也不要因此而尽量多的开线程,因为理论上32位Windows平台上单个进程所能访问的最大内存量是4G,但是操作系统需要给系统核心分配2G的空间,所以一般用户程序最大可以访问的内存大小为2G。而每一个线程默认情况下会占用1M的栈空间,这意味着程序中使用的线程在理论上也只有2000个,而在实际开发中会发现1930个左右的线程都会出现内存不足的异常。
 不过这个数目已经很大了,能够满足我们的日常要求,而且在你需要特别多的线程时,你也可以采用变向的操作方式来实现。我们可以通过任务管理器来查看线程占用的进程数目(别说你的任务管理器中没这一列,这一列是手动添加了,在“查看”----“选择列”下)。如下图1:
 
              图 1
3 .Net中的多线程
 .Net中,所有多线程的操作均在System.Threading命令空间下,并且主要集中在Thread这个类中,一个Thread表示一个线程。Thread中的几个主要属性和方式我会在示例中一一说明。
4 线程的创建
线程是通过ThreadStart委托来创建的,当然能用委托,也就意味着可以用匿名方法或者Lambda也能创建,那么我用这三种方式来用多线程输出HelloWord。
第一种方式:直接用ThreadStart委托:

        static void Main()
        {
            Thread t = new Thread(new ThreadStart(SayHello));
            t.Start();
        }
        private static void SayHello()
        {
            System.Console.WriteLine("Hello!");
        }

第二种方式:用匿名方法:
        static void Main()
        {
            Thread t = new Thread(delegate()
            {
                Console.WriteLine("Hello!");
            });
            t.Start();
        }

 

第三种方法:Lambda表达式
        static void Main()
        {
            Thread t = new Thread(() => System.Console.WriteLine("Hello"));
            t.Start();
        }


5 Thread的基本讲解:

 Thread中的几个重要的方法:

 Start:使线程得以按计划执行

 Sleep:将当前线程阻塞指定的毫秒数

 Join:阻塞调用线程,直到某个线程终止时为止

 Abort:调用此方法通常会终止线程

 由于Sleep操作的是当前线程,所以它为静态方法。

 

 Thread中的几个重要的属性:

 CurrentThread:获取当前正在运行的线程(静态方法)

 IsAlive:获取一个值,该值指示当前线程的执行状态

 IsBackground:获取或设置一个值,该值指示某个线程是否为后台线程

 CurrentContext:获取线程正在其中执行的当前上下文

 Priority:获取或设置一个值,该值指示线程的调度优先级

 ThreadState:获取一个值,该值包含当前线程的状态。 

以上均摘自MSDN

6多线程的分类
  MSDN中解释:一个线程或者是后台线程或者是前台线程(通过IsBackground属性来设置前台或后台)。后台线程与前台线程类似,区别是后台线程不会防止进程终止。属于某个进程的所有前台线程都终止后,公共语言运行库就会结束该进程。所有剩余的后台线程都会停止且不会完成。那么我们来做个测试,这个Demo原型来源于MSDN:

前台线程和后台线程
class Program
{
static void Main()
{
BackgroundTest shortTest
= new BackgroundTest(10);
Thread foregroundThread
=
new Thread(new ThreadStart(shortTest.RunLoop));
foregroundThread.Name
= "ForegroundThread";

BackgroundTest longTest
= new BackgroundTest(100);
Thread backgroundThread
=
new Thread(new ThreadStart(longTest.RunLoop));
backgroundThread.Name
= "BackgroundThread";
backgroundThread.IsBackground
= true;

foregroundThread.Start();
backgroundThread.Start();
}
}

class BackgroundTest
{
int maxIterations;

public BackgroundTest(int maxIterations)
{
this.maxIterations = maxIterations;
}

public void RunLoop()
{
String threadName
= Thread.CurrentThread.Name;

for (int i = 0; i < maxIterations; i++)
{
Console.WriteLine(
"{0} count: {1},{2}",
threadName, i.ToString(), Thread.CurrentThread.ThreadState.ToString());
Thread.Sleep(
250);
}
Console.WriteLine(
"{0} finished counting.", threadName);
}
}

 

这个demo中有两个线程,一个循环10次,一个打循环100将,你认为最后输出的是什么呢?看下图:

截这个图还真不容易,因为每次执行到这儿的时候就会自动结束程序,只循环了10次。为什么呢?因为前台线程循环了10次后完成了任务,CLR就会终止后台线程,此程序就此结束。

那么我们再试试吧,在上面的那段代码的最后一行再加上一行代码:

System.Console.ReadLine()呢?大家试下,这次的执行结果就完全不同了,因为前台的任务还没有执行完,在等待用户的进一步输入,所以后台线程依然会继续执行下去。

 

今天就先写这多了,下一篇正在酝酿之中,欢迎大家指点。

posted @ 2010-05-22 18:15  ReadQi  阅读(531)  评论(0编辑  收藏  举报