zoukankan      html  css  js  c++  java
  • 多线程系列(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()呢?大家试下,这次的执行结果就完全不同了,因为前台的任务还没有执行完,在等待用户的进一步输入,所以后台线程依然会继续执行下去。

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

  • 相关阅读:
    MyEclipse启动时,报错Error:could not open`E:Program FilesJavaJAVAlibamd64jvm.cfg'
    换JDK以后,MyEclipse无法启动,报错:Failed to load the JNI...
    ORA-12514
    java语言
    基本数据类型
    C# 计算时间间隔,两个时间差(年月日时分秒)
    Java的Stream流
    Java的Lambda表达式和函数式接口
    Java中的Log
    Oracle的触发器Trigger
  • 原文地址:https://www.cnblogs.com/Deper/p/1741650.html
Copyright © 2011-2022 走看看