1、Thread类可以创建和控制线程。Thread构造函数进过重载可接受ThreadStart类或者ParameterizedThreadStart类型的委托参数。
2、ThreadStart委托接受的函数签名为:返回void,无参
3、在创建Thread对象之后,调用Start方法就可以启动线程
4、用ThreadStart委托对象创建Thread的例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ThreadStart _func = func;
Thread t = new Thread(_func);
t.Start();
//可以简化
Thread t1 = new Thread(func);
t1.Start();
//还可以简化
Thread t2 = new Thread(() =>
{
Console.WriteLine("thread func running");
Thread.Sleep(5000);
Console.WriteLine("thread func finish");
});
t2.Start();
}
static void func()
{
Console.WriteLine("thread func running");
Thread.Sleep(5000);
Console.WriteLine("thread func finish");
}
}
}
5、ParameterizedThreadStart是可以带参的。它接受的函数签名为:返回void,输入object对象。
例子如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Para pa = new Para();
pa.str = "yuyong";
pa.index = 2;
Thread t = new Thread(func);
t.Start(pa);
Console.ReadKey();
}
static void func(object o)
{
Console.WriteLine("thread func running");
Para pa = (Para)o;
Thread.Sleep(5000);
Func<char, bool> c = printResult;
c(pa.str.ToArray()[pa.index]);
Console.WriteLine("thread func finish");
}
static bool printResult(char c)
{
Console.WriteLine(c);
return true;
}
class Para
{
public string str { get; set; }
public int index { get; set; }
}
}
}
6、给Thread带上输入参数的另一种方式是定义一个类,让这个类的某个成员方法称为线程的异步任务。例子如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyThreadFunc myFunc = new MyThreadFunc("yuyong", 2, printResult);
Thread t = new Thread(myFunc.Func);
Console.WriteLine("Thread started");
t.Start();
Console.ReadKey();
}
static bool printResult(char c)
{
Console.WriteLine(c);
Console.WriteLine("Thread finish");
return true;
}
}
class MyThreadFunc
{
private string str;
private int index;
private Func<char, bool> result_func;
public MyThreadFunc(string s, int i, Func<char, bool> func)
{
str = s;
index = i;
result_func = func;
}
public void Func()
{
Thread.Sleep(5000);
result_func(str.ToArray()[index]);
}
}
}
7.后台线程
只要有一个前台进程在运行,应用程序进程就在运行。
例如,有多个前台线程在运行,而Main方法结束了,应用程序仍然激活的,直到全部前台线程完成为止。
对于后台线程来说则不是这样,当主线程(Main方法所在的线程)结束时,不管后台线程有没有完成,都会应用程序进程都会立即终止。
默认情况下,Thread类创建的线程是前台线程(这一点可以手动改变),线程池中的线程总是后台线程(这一点不可以手动改变)。
在用Thread创建线程时,可以通过设置其IsBackground属性来确定它是前台还是后台线程。
8、线程优先级
优先级高的线程有更大的概率被线程调度器调度获得CPU资源。
在Thread类可以设置Priority属性,影响线程的基本优先级。Priority属性的值是ThreadPriority的一个枚举值。
9、线程控制
可以调用Thread.ThreadState属性来查看当钱线程的状态。
可以使用Thread.Sleep方法使当前线程休眠指定时间。
10、线程池
可以借助ThreadPool类托管线程资源。这个类会在需要时增加线程池中的线程数,直到最大线程数。线程池中的最大线程数是可以配置的,也可以指定创建线程池时应启动的最小线程数。如果线程池中的线程个数利用达到了极限,那么新的任务就需要排队。
使用线城池时,调用ThreadPool.QueueUserWorkItem方法传入一个WaitCallBack类型的委托。线程池在接收到这个请求的时候就会从线程池中选择一个线程来调用该委托指向的方法。
例如:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int maxThr = -1;
int ioThr = -1;
//查询ThreadPool允许的最大工作线程数和最大IO线程数
ThreadPool.GetMaxThreads(out maxThr, out ioThr);
Console.WriteLine("最大工作线程数{0},最大IO线程数{1}", maxThr, ioThr);
//设置ThreadPool启动时最小的工作线程数和最小的IO线程数
ThreadPool.SetMinThreads(10, 10);
Para pa = new Para();
pa.str = "yuyong";
pa.index = 2;
//public delegate void WaitCallback(object state);
WaitCallback w = func;
//传入委托,传入输入参数
ThreadPool.QueueUserWorkItem(w, pa);
Console.ReadKey();
}
static void func(object o)
{
Console.WriteLine("thread func running");
Para pa = (Para)o;
Thread.Sleep(5000);
Func<char, bool> c = printResult;
c(pa.str.ToArray()[pa.index]);
Console.WriteLine("thread func finish");
}
static bool printResult(char c)
{
Console.WriteLine(c);
return true;
}
class Para
{
public string str { get; set; }
public int index { get; set; }
}
}
}
结果如下
使用线程池时要注意:
a、线程池中的线程都是后台线程,不能把线程池中的线程改成前台线程。
b、不能给线程池中的线程设置优先级或者名称
c、线程池只能用于时间较短的任务,如果需要一直运行的线程应当使用Thread类创建。