兩種新建線程的簡單方法以及懶漢模式中lock的重要性

先扔代碼吧。。。

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,說明已經創建完,不再創建。這樣纔算是只創建了一個對象。

所以無論是寫什麼樣的代碼,一旦涉及多線程,一定要多運行幾次,看看會不會出錯誤,因爲多線程的隨機化真的很難預測。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章