参考链接:
http://blog.youkuaiyun.com/jasonvip_c/article/details/5718636
http://www.cnblogs.com/miniwiki/archive/2010/06/18/1760540.html
1.前台线程与后台线程
Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
一个线程是前台线程还是后台线程可由它的IsBackground属性来决定。这个属性是可读又可写的。它的默认值为false,即意味着一个线程默认为前台线程。我们可以将它的IsBackground属性设置为true,从而使之成为一个后台线程。
示例:
using System;
using System.Threading;
class ThreadTest11
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(Go);
//若添加这句话,则创建完十个线程之后就会退出控制台程序
//若注释这句话,则等待五秒后就会退出控制台程序
//t.IsBackground = true;
t.Start();
}
}
static void Go()
{
DateTime start = DateTime.Now;
while ((DateTime.Now - start).Seconds < 5) ;
}
}
既然前台线程和后台线程有这种差别,那么我们怎么知道该如何设置一个线程的IsBackground属性呢?下面是一些基本的原则:对于一些在后台运行的线程,当程序结束时这些线程没有必要继续运行了,那么这些线程就应该设置为后台线程。比如一个程序启动了一个进行大量运算的线程,可是只要程序一旦结束,那个线程就失去了继续存在的意义,那么那个线程就该是作为后台线程的。而对于一些服务于用户界面的线程往往是要设置为前台线程的,因为即使程序的主线程结束了,其他的用户界面的线程很可能要继续存在来显示相关的信息,所以不能立即终止它们。这里我只是给出了一些原则,具体到实际的运用往往需要编程者的进一步仔细斟酌。
2.线程与进程
一个不错的解释:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
简单地说,就是:
一个系统可以执行多个进程,允许多个任务同时运行
一个进程可以执行多个线程,允许任务分成不同的部分运行
一个进程的内存空间是共享的,每个线程都可以使用这些共享内存
3.何时使用多线程
多线程程序一般被用来在后台执行耗时的任务。主线程保持运行,并且工作线程做它的后台工作。对于Windows Forms程序来说,如果主线程试图执行冗长的操作,键盘和鼠标的操作会变的迟钝,程序也会失去响应。由于这个原因,应该在工作线程中运行一个耗时任务时添加一个工作线程,即使在主线程上有一个有好的提示“处理中...”,以防止工作无法继续。这就避免了程序出现由操作系统提示的“没有相应”,来诱使用户强制结束程序的进程而导致错误。
4.何时不使用多线程
多线程也同样会带来缺点,最大的问题是它使程序变的过于复杂,拥有多线程本身并不复杂,复杂是的线程的交互作用,这带来了无论是否交互是否是有意的,都会带来较长的开发周期,以及带来间歇性和非重复性的bugs。因此,要么多线程的交互设计简单一些,要么就根本不使用多线程。除非你有强烈的重写和调试欲望。
当用户频繁地分配和切换线程时,多线程会带来增加资源和CPU的开销。
5.线程优先级
public enum ThreadPriority有五种取值,按优先级从高到低为:
Highest > AboveNormal > Normal Below > Normal > Lowest
using System;
using System.Threading;
class ThreadTest12
{
static void Main()
{
PriorityTest priorityTest = new PriorityTest();
ThreadStart startDelegate = new ThreadStart(priorityTest.ThreadMethod);
Thread threadOne = new Thread(startDelegate);
threadOne.Name = "ThreadOne";
Thread threadTwo = new Thread(startDelegate);
threadTwo.Name = "ThreadTwo";
threadTwo.Priority = ThreadPriority.BelowNormal;
threadOne.Start();
threadTwo.Start();
// Allow counting for 3 seconds.
Thread.Sleep(3000);
priorityTest.LoopSwitch = false;
Console.Read();
}
}
class PriorityTest
{
bool loopSwitch;
public PriorityTest()
{
loopSwitch = true;
}
public bool LoopSwitch
{
set { loopSwitch = value; }
}
public void ThreadMethod()
{
long threadCount = 0;
while (loopSwitch)
{
threadCount++;
}
Console.WriteLine("{0} with {1,11} priority " +
"has a count = {2,13}", Thread.CurrentThread.Name,
Thread.CurrentThread.Priority.ToString(),
threadCount.ToString("N0"));
}
}
运行结果:
6.异常处理
using System;
using System.Threading;
class ThreadTest13
{
static void Main(string[] args)
{
try
{
new Thread(Go).Start();
}
catch (Exception ex)
{
Console.WriteLine("Exception");
}
}
static void Go()
{
throw null;
}
}
这里try/catch语句一点用也没有,新创建的线程会引发NullReferenceException异常
正确的捕获异常的方法是:
using System;
using System.Threading;
class ThreadTest13
{
static void Main(string[] args)
{
new Thread(Go).Start();
}
static void Go()
{
try
{
throw null;
}
catch (Exception ex)
{
Console.WriteLine("Exception");
Console.Read();
}
}
}