先扔代碼吧。。。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;//Parallel類
namespace ThreadDemo
{
class Program
{
static void Main(string[] args)
{
ThreadDemo[] array = new ThreadDemo[10];
for (int i = 0; i < 10; i++)
//array[i] = new CreateOnlyOneThread();
array[i] = new CreateOnlyOneInvoke();
Parallel.ForEach(array, i => i.Start());
Console.ReadLine();
}
}
interface ThreadDemo
{
void Start();
}
class CreateOnlyOneThread : ThreadDemo
{
private Thread thread;
private delegate void CreateOnlyOneThreadMethod();
public void GetOnlyOne()
{
OnlyOne.GetOnlyOne();
}
public void Start()
{
CreateOnlyOneThreadMethod createOnlyOneThreadMethod = GetOnlyOne;
thread = new Thread(new ThreadStart(createOnlyOneThreadMethod));
thread.IsBackground = true;
thread.Start();
}
}
class CreateOnlyOneInvoke : ThreadDemo
{
IAsyncResult iar;
private delegate void CreateOnlyOneInvokeMothed();
public void GetOnlyOne()
{
OnlyOne.GetOnlyOne();
}
public void Start()
{
CreateOnlyOneInvokeMothed createOnlyOneInvokeMothed = GetOnlyOne;
iar = createOnlyOneInvokeMothed.BeginInvoke(null, null);
}
}
class OnlyOne
{
private static OnlyOne onlyone;
private static object obj= new object();
private OnlyOne()
{
Console.WriteLine("Create!");
}
public static OnlyOne GetOnlyOne()
{
if (onlyone==null)
lock(obj)
{
if (onlyone==null)
onlyone=new OnlyOne();
}
return onlyone;
}
}
}
上面的代碼中CreateOnlyOneThread類和CreateOnlyOneInvoke類分別是兩種新建線程的方法,感覺都挺好上手的,但是他們都有一個共同的特點就是要用委託。
但是效果上有點不同
BeginInvoke方法創造出來的子線程可以理解爲 他的IsBackGround爲True,也就是說如果主線程(這裏面是Main)結束的話,不管子線程有沒有執行完畢都會退出。
而Thread,Start()的線程是可以調的,如果IsBackGround爲false,那麼即使主線程結束,仍然會等待子線程結束。
但是如果做得不是控制檯而是Windows程序的話,這種情況直接alt+F4,打開任務管理器發現進程仍然還在!
然後再說下lock的事。。。
一般都是用lock(this)的。。。但是由於是靜態方法,所以只能新建一個靜態的object對象。
第一層是判斷當前是否已經創建OnlyOne的對象,如果沒有創建,那麼向下執行。
然後問題來了,既然已經鎖住了,那麼還加一層判斷幹什麼?這正是多線程麻煩的地方。。。
如果一個線程,我們大概可以在腦中模擬出程序執行的過程,但是如果是多線程的話,就不一樣了。。。因爲即使是隻添加一個線程,程序運行的結果就已經不能預測得到的了。所以一般調多線程的程序都不用debug。。。
回到主題,打個比方,有一個400米賽跑比賽,比賽規定:1、如果有人完成比賽,那麼設在100米檢查點(也就是第一個 if (onlyOne==null) )就禁止選手通過(就是對象已經穿件完畢,不用在創建了)。2、如果有人已經通過了200米檢查點,那麼其他選手要在200檢查點處等待,直到那個通過200,米檢查點的選手完成比賽,才允許下一個選手通過200米檢查點(也就是lock(obj){}的那塊)。
如果是普通的單線程的話,就是第一個人先跑,跑到終點之後第二個再跑。這樣按照規則,因爲第一個人已經完成了比賽,所以第二個,第三個,以及他們後面的都無法通過100米的檢查點。但是現在不同,現在是所有人一起跑,所以當有人第一個通過終點前肯定也有人已經也跑過了100米的檢查點,這個時候大家來到了200米的檢查點,由於先前通過200米檢查點的人沒有通過終點,所以大家(衆線程)只好等待(這個也就是lock的作用),直到那個人通過重點(創建完對象,解鎖),纔會有下一個人通過200米檢查點。這個時候第二個 if (onlyOne==null) 的作用就體現出來了,如果之前沒有創建,那麼onlyOne爲null,創建對象,如果不爲null,說明已經創建完,不再創建。這樣纔算是只創建了一個對象。
所以無論是寫什麼樣的代碼,一旦涉及多線程,一定要多運行幾次,看看會不會出錯誤,因爲多線程的隨機化真的很難預測。