程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 多線程系列一,多線程系列

多線程系列一,多線程系列

編輯:C#入門知識

多線程系列一,多線程系列


線程,進程,關系我不就不在BB了。

關於線程,其實我相信大家都了解了很多,此處我只是發表我對線程的理解和認識,不喜勿噴。如有不對之處還請大家指出。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Thread t = new Thread(Runing);
 6             t.Name = "測試線程";
 7             t.Start();
 8             Console.ReadLine();
 9         }
10 
11         static void Runing()
12         {
13             Console.WriteLine(Thread.CurrentThread.Name + " :" + DateTime.Now.ToString());
14         }
15     }

上述代碼大家肯定都不陌生~!

 接下來我們修改一下程序,完成單線程處理任務。我們知道很多時候,當我們的程序設計,又多個客戶端或者稱多個請求來源,並發請求來了以後,我們需要按照隊列處理事情比如秒殺下單

public class MyThread1
    {
        //通知一個或多個正在等待的線程已發生事件
        ManualResetEvent mre = new ManualResetEvent(false);
        //服務器的運行標識
        bool isRuning = true;
        //線程安全的隊列
        System.Collections.Concurrent.ConcurrentQueue<string> cqueue = new System.Collections.Concurrent.ConcurrentQueue<string>();

        public MyThread1()
        {
            Thread t = new Thread(RunTest);
            t.Name = "我是測試線程";
            t.Start();
        }

        //模擬新增任務
        public void add(int i)
        {
            //添加任務到隊列
            cqueue.Enqueue("" + i);
            //喚醒所有相關的掛起線程
            mre.Set();
        }


        static void Main(string[] args)
        {
            MyThread1 p = new MyThread1();
            for (int i = 0; i < 10; i++)
            {
                p.add(i);
            }
            Console.ReadLine();
        }

        void RunTest()
        {
            //主循環 服務器運行標識
            while (isRuning)
            {
                //如果是空則繼續等待      服務器運行標識
                while (cqueue.IsEmpty && isRuning)
                {
                    Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + "  sleep");
                    //重置線程暫停狀態
                    mre.Reset();
                    //這個操作是以便服務器需要停止操作,
                    //如果停止調用線程的Thread.Abort()是會導致處理隊列任務丟失
                    mre.WaitOne(2000);
                }
                string ret;
                //取出隊列任務
                if (cqueue.TryDequeue(out ret))
                {
                    //測試輸出任務
                    Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + "  " + ret);
                }
            }
        }
    }

通過add實現並發下單 RunTest() 方法來實現處理邏輯,

此處通過 ManualResetEvent 實現對線程的掛起和喚醒操作。當隊列為空的時候,線程自動進入掛起狀態,當有新的任務,add操作的時候直接喚醒掛起的線程。立即進入處理狀態。

為什麼選用 ManualResetEvent 這個線程通知這裡就不在解釋了有興趣的可以自己百度~!

為了避免在需要關閉服務器的時候調用線程的Thread.Abort() 導致後續隊列操作失效,所以加入了isRuning的bool變量實現線程是否繼續運行。

 

上述功能僅僅是永遠類似於處理下單,需要單線程隊列處理情況。各位看官請自行分析需求~~!

有了上述單線程處理隊列需求,我們也許會想到那麼在程序運行中自然有多線程處理隊列。

比如我們記錄日志的情況,(打個比方而已如果你很喜歡log4Net or log4J 請繞道)  我們需要提交日志記錄,但是不想這個操作耽誤程序的正常運行,且想日志這樣的記錄程序肯定不能單一線程處理,

如果日志瘋狂記錄,那麼勢必會導致處理不及時內存暴漲溢出問題

於是再次修改一下程序

 1 public class MyThread3
 2     {
 3         //通知一個或多個正在等待的線程已發生事件
 4         ManualResetEvent mre = new ManualResetEvent(false);
 5         //服務器的運行標識
 6         bool isRuning = true;
 7         //線程安全的隊列
 8         System.Collections.Concurrent.ConcurrentQueue<string> cqueue = new System.Collections.Concurrent.ConcurrentQueue<string>();
 9         //計數存儲器
10         Dictionary<string, int> cdic = new Dictionary<string, int>();
11 
12         public MyThread3()
13         {
14             List<Thread> ts = new List<Thread>();
15             for (int i = 0; i < 4; i++)
16             {
17                 Thread t = new Thread(RunTest);
18                 t.Name = "我是線程(" + i + ")";
19                 cdic[t.Name] = 0;
20                 t.Start();
21                 ts.Add(t);
22             }
23         }
24 
25         //模擬新增任務
26         public void Add()
27         {
28             Thread t1 = new Thread(() =>
29             {
30                 for (int i = 0; i < 40; i++)
31                 {
32                     //添加任務到隊列
33                     cqueue.Enqueue("日志記錄 " + i);
34                     //喚醒所有相關的掛起線程
35                     mre.Set();
36                 }
37 
38             });
39             t1.Start();
40 
41         }
42 
43         //輸出計數器
44         public override string ToString()
45         {
46             foreach (var item in cdic)
47             {
48                 Console.WriteLine(item.Key + " 計數 " + item.Value);
49             }
50             return "";
51         }
52 
53 
54         static void Main(string[] args)
55         {
56             MyThread3 p = new MyThread3();
57             p.Add();
58             Console.ReadLine();
59             p.ToString();
60             Console.WriteLine();
61             Console.ReadLine();
62         }
63 
64         void RunTest()
65         {
66             //主循環 服務器運行標識
67             while (isRuning)
68             {
69                 //如果是空則繼續等待      服務器運行標識
70                 while (cqueue.IsEmpty && isRuning)
71                 {
72                     //重置線程暫停狀態
73                     mre.Reset();
74                     //這個操作是以便服務器需要停止操作,
75                     //如果停止調用線程的Thread.Abort()是會導致處理隊列任務丟失
76                     mre.WaitOne(2000);
77                     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + "  sleep");
78                 }
79                 string ret;
80                 //取出隊列任務
81                 if (cqueue.TryDequeue(out ret))
82                 {
83                     //測試輸出任務
84                     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + "  " + ret);
85                     //添加任務的計數器,為了查看最後線程執行任務的計數
86                     cdic[Thread.CurrentThread.Name] = cdic[Thread.CurrentThread.Name] + 1;
87                 }
88             }
89         }
90     }

輸出

多個線程實現了對日志記錄處理,並且在空閒時間實現線程暫停,有任務喚醒,以保證,不浪費資源同時能即時處理~!

由於第一次寫博客,語言組織能力差,大家就看看程序代碼和注釋吧!

大家多多指教。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved