线程 实用的基础篇

Posted 无忧岛主

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程 实用的基础篇相关的知识,希望对你有一定的参考价值。

主要讲述三点:

一,任务,线程,进程,线程的概念和关系

二,线程主要属性和方法

三,线程的创建,参数的传递和返回值的接收

 

一、任务,程序,进程,线程

任务是什么?

任务:交派的工作,这里是指软件为达到某个目的的一系列操作。一个任务可以是一个进程,也可以是一个线程,还可以是一个简单的程序。

多任务:指操作系统一次运行多个应用程序的能力。比如现在的电脑可以同时开多个窗口就是多任务的表现。

不再详细解释。

程序是什么?

程序:一组指令的有序集合,简而言之就是指令集。

不再详细解释。

进程是什么?

进程是程序执行环境的总和。

解释一下,这个执行环境我们可以把它看做一个操作系统为程序分配的运行物理隔离区。在这个隔离区为其分配标志ID,内存,CPU等程序运行所需的各项资源。进行物理隔离的好处是防止其他进程修改另一个进程的数据。使进程之间互不影响。

举个栗子,我要做一个蛋糕,我有做一个做生日蛋糕的食谱,厨房里有所需的原料(面粉鸡蛋神马的),这个时候我就是处理器,食谱就是程序,原料就是输入,放原料的厨房就是内存。进程么就是我阅读食谱根据拿来的原料在厨房进行烘烤蛋糕这一系列流程的总和。

线程是什么?

线程是某一个进程单独运行的指令集

解释一下,我们知道我们写的程序代码以Main()函数为入口自上而下执行。而线程是一种特殊的对象,它是操作系统执行多任务的一部分,它允许应用程序一部分对立其他对象而单独运行,因此也就脱离了应用程序常规的执行顺序

举个栗子看下面一段代码

 public  class Class1
    {
      public void TestMain()
      {
          task();//先执行
          DoData();//后执行
      }
      public void ThreadMain()
      {
          Thread thread = new Thread( new ThreadStart(task));
          thread.Start();
          DoData();
      }
      public void task() { }   //里面逻辑省略
      public void DoData() { }//里面逻辑省略
     
    }

正常情况下就是TestMain()这个方法先执行task,后执行DoData而且是必须等task方法执行完才能执行DoData方法。

而ThreadMain用了线程以后调用task方法,那么它就可以单独运行,DoData不需要等待task执行完毕就可以执行。

线程和进程的关系

可以用下图表示

对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难。(引自:http://lavasoft.blog.51cto.com/62575/27069/)

二、了解线程

线程的构建函数,属性和方法,可以参考MSDN:https://msdn.microsoft.com/zh-cn/library/system.threading.thread(v=vs.110).aspx

这里学习一下主要一些东西。

创建线程的构造函数:

 名称说明
System_CAPS_pubmethod Thread(ParameterizedThreadStart)

初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。

System_CAPS_pubmethod Thread(ParameterizedThreadStart, Int32)

初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小。。

System_CAPS_pubmethod Thread(ThreadStart)

初始化 Thread 类的新实例。

System_CAPS_pubmethod Thread(ThreadStart, Int32)

初始化 Thread 类的新实例,指定线程的最大堆栈大小。

线程的常用属性:

 名称说明
System_CAPS_pubproperty IsAlive

获取指示当前线程的执行状态的值。

System_CAPS_pubproperty Priority

获取或设置指示线程的调度优先级的值。

System_CAPS_pubproperty ThreadState

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

线程常用方法:

   其实就是线程的启动,终止,中断,等待,挂起

名称说明
System_CAPS_pubmethod Abort()

在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。

System_CAPS_pubmethod Interrupt()

中断处于 WaitSleepJoin 线程状态的线程。

System_CAPS_pubmethod Join()

阻止调用线程,直到此实例所表示的线程终止,同时继续执行标准的 COM 和 SendMessage 泵处理期间。

System_CAPS_pubmethod Join(Int32)

阻止调用线程,直到此实例所表示的线程终止或经过指定的时间,同时继续执行标准的 COM 和 sendmessage 消息泵处理。

System_CAPS_pubmethod Join(TimeSpan)

阻止调用线程,直到此实例所表示的线程终止或经过指定的时间,同时继续执行标准的 COM 和 sendmessage 消息泵处理。

System_CAPS_pubmethodSystem_CAPS_static ResetAbort()

取消当前线程所请求的 Abort

System_CAPS_pubmethodSystem_CAPS_static Sleep(Int32)

将当前线程挂起指定的毫秒数。

System_CAPS_pubmethodSystem_CAPS_static Sleep(TimeSpan)

将当前线程挂起指定的时间。

System_CAPS_pubmethod Start()

导致操作系统将当前实例的状态更改为 ThreadState.Running

   a.当我们调用Thread对象的Start()方法的时候,公共语言运行库会将一个时间片分配给传递到Thread对象的构造函数的方法地址。这句话很重要也就是调用方法的时间不是创建线程的时候,而是线程启动的时候。还要明白一点线程并不是

按照启动的先后顺序结束的。

  b.线程启动的时候线程将处于运行(Running)状态,当操作系统处理线程时,他就可以进入睡眠(Sleep)或终止(Abort)的状态。你可以调用Thread.Sleep()方法对当前线程进行休眠。那么在休眠时间到达之前线程将一直处于WaitSleepJoin状态。

c.如果你想在到达指定的睡眠之前唤醒线程,你可以使用Interrupt()方法。Interrupt可以将线程放回调度队列中。

d.Abort()方法可以用来销毁当前线程,如果因某种原因(比如线程执行了太长时间或用户选择取消)要终止线程就可以用Abort方法。

 

 

 

三、创建线程(创建线程的几种方法总结)

(1)无传递参数,无返回参数

ThreadStart threadStart=new ThreadStart(Task);
Thread thread=new Thread(threadStart);
thread.Start(); 

public void Task(){
//
} 
简化版可以直接写成:
Thread thread=new Thread(new ThreadStart(Task)); 

thread.Start();

public void Task(){ // }

(2)传递单个参数(利用ParameteriizedThreadStart来构建)

ParameterizedThreadStart threadStart=new ParameterizedThreadStart(Calculate)
Thread thread=new Thread()
thread.Start(0.9); 

public void Task(object arg){
double Diameter=double(arg);

}

(3)传递多个参数

第一种:使用专门的线程类。

把线程调用的方法和所需的参数放到一个类中。调用的方法是类的方法,参数是类的属性。建立一个带参数的构造函数,这样就可以把参数作为构建函数的参数传入类的属性里。

public  class Class1
    {
     
      public void ThreadMain()
      {
          MyThread t=new MyThread(3,4);
          ThreadStart threadStart = new ThreadStart(t.Task);
          Thread thread=new Thread(threadStart);
          thread.Start();
      }
       
    }
  public class MyThread
  {
      public double Diameter = 10;

      public double Result = 0;
      public int Width { get; set; }
      public int Height { get; set; }

      public MyThread(int width,int height)
      {
          Width = width;
          Height = height;
      }

      public void Task()
      {
          int Area = Width * Height;
      }
  }

第二种方法:通过使用委托委托

  public  class Class1
  {  
      public void ThreadMain()
      {
          Thread thread = new Thread(new ThreadStart(delegate() { Task(3, 4); }));
          thread.Start();
      }
       public void Task(int Width,int Height)
       {
          int Area = Width * Height;
       }     
    }   

(4)需要传递参数且需要返回参数

首先把需要异步调用的方法定义为一个委托,然后利用BeginInvoke来异步调用,最后用EndInvoke来接收返回值

namespace Sx.WF
{
   delegate int DeleTask(int Width,int Height);
  public  class Class1
  {
      static DeleTask task;
      public static int Area = 0;
      public void ThreadMain(int Width, int Height)
      {
          task = new DeleTask(Task);
          task.BeginInvoke(Width, Height,new AsyncCallback(TaskFinished), null);
          Thread thread = new Thread(new ThreadStart(delegate() { task(Width, Height); }));
          thread.Start();
      }
       public static int Task(int Width,int Height)
       {
          int Area = Width * Height;
          return Area;
       }
       public static void TaskFinished(IAsyncResult result)
       {
           Area = task.EndInvoke(result);
       }

    }   
  }

 

以上是关于线程 实用的基础篇的主要内容,如果未能解决你的问题,请参考以下文章

基础篇:异步编程不会?我教你啊!CompeletableFuture

03讲基础篇:经常说的CPU上下文切换是什么意思(上)

并发编程之多线程基础篇及面试

java基础篇之nio与aio

JAVA SE基础篇61.多线程相关1

Java多线程编程(基础篇)