C# 线程相关知识总结

2020-06-17 15:24:00王振洲

如:

class ThreadTest
{
 //全局变量
 int i;
 
 static void Main()
 {
  ThreadTest tt = new ThreadTest();  // 创建一个ThreadTest类的实例
  new Thread (tt.Go).Start();
  tt.Go();
 }
 
 // Go方法属于ThreadTest的实例
 void Go() 
 {
   if (i==1) { ++i; Console.WriteLine (i); }
 }
}

输出

2

新线程和主线程上调用了同一个实例的Go方法,所以变量i共享。

静态变量也可以被多线程共享

class ThreadTest 
{
 static int i;  // 静态变量可以被线程共享
 
 static void Main()
 {
  new Thread (Go).Start();
  Go();
 }
 
 static void Go()
 {
  if (i==1) { ++i; Console.WriteLine (i); }
 }
}

输出

2

如果将Go方法的代码位置互换

 static void Go()
 {
  if (i==1) { Console.WriteLine (i);++i;}
 }

输出

1 1(有时输出一个,有时输出两个)

如果新线程在Write之后,done=true之前,主线程也执行到了write那么就会有两个done。

不同线程在读写共享字段时会出现不可控的输出,这就是多线程的线程安全问题。

解决方法: 使用排它锁来解决这个问题--lock

class ThreadSafe 
{
 static bool done;
 static readonly object locker = new object();
 
 static void Main()
 {
  new Thread (Go).Start();
  Go();
 }
 
 static void Go()
 {
  //使用lock,确保一次只有一个线程执行该代码
  lock (locker)
  {
   if (!done) { Console.WriteLine ("Done"); done = true; }
  }
 }
}

当多个线程都在争取这个排它锁时,一个线程获取该锁,其他线程会处于blocked状态(该状态时不消耗cpu),等待另一个线程释放锁时,捕获该锁。这就保证了一次
只有一个线程执行该代码。

Join和Sleep

Join可以实现暂停另一个线程,直到调用Join方法的线程结束。

static void Main()
{
 Thread t = new Thread (Go);
 t.Start();
 t.Join();
 Console.WriteLine ("Thread t has ended!");
}
 
static void Go()
{
 for (int i = 0; i < 1000; i++) Console.Write ("y");
}

输出

yyyyyy..... Thread t has ended!

线程t调用Join方法,阻塞主线程,直到t线程执行结束,再执行主线程。

Sleep:暂停该线程一段时间

Thread.Sleep (TimeSpan.FromHours (1)); // 暂停一个小时
Thread.Sleep (500);           // 暂停500毫秒

Join是暂停别的线程,Sleep是暂停自己线程。

上面的例子是使用Thread类的构造函数,给构造函数传入一个ThreadStart委托。来实现的。

public delegate void ThreadStart();

然后调用Start方法,来执行该线程。委托执行完该线程也结束。

如:

class ThreadTest
{
 static void Main() 
 {
  Thread t = new Thread (new ThreadStart (Go));
 
  t.Start();  // 执行Go方法
  Go();    // 同时在主线程上执行Go方法
 }
 
 static void Go()
 {
  Console.WriteLine ("hello!");
 }
}