1. 程式人生 > >C#線程--5.0之前時代(二)、線程的同步

C#線程--5.0之前時代(二)、線程的同步

strong spa 安全 對象 方法 new 常見 left ado

線程同步

說明:接上一篇,註意分享線程同步的必要性和線程同步的方法。

一、什麽是線程同步:

在同一時間只允許一個線程訪問資源的情況稱為線程同步。

二、為什麽需要線程同步:

  • 避免競爭條件;
  • 確保線程安全;(如果兩個線程同時訪問一個資源並對那個資源做修改,就不安全了)

現在的計算機變得越來越多核,每一個CPU可以獨立工作,但是對於內存和外部資源、數據庫的訪問卻可能因為不同線程的訪問使數據產生異常,常見的例子就是銀行的轉賬的例子不再贅述。

三、線程同步的方法:

  • 同步代碼中重要的部分;
  • 使對象不可改變;
  • 使用線程安全包裝器;

    註意:局部變量、方法參數和返回值是放在堆棧中的,本身是線程安全的。

四、線程不安全的演示:

背景:在數據庫的user_blance表插入兩條數據,兩人的balance值都為3000.00,整個user_balance表的balance總值為6000.00

        static string connectionStr = "Server=127.0.0.1;Port=3306;Stmt=;Database=exe_dev; User=root;Password=123456";
        public static void UnSafeThread() {
            Thread ThreadOne = new Thread(new ThreadStart(DrawMoney));
            ThreadOne.Name 
= "A001"; Thread ThreadTwo = new Thread(new ThreadStart(DrawMoney)); ThreadTwo.Name = "A002"; ThreadOne.Start(); ThreadTwo.Start(); string sumMonney = "select sum(balance) from user_balance"; int count = 0; while (count < 200
) { using (MySqlConnection conn = MySqlConnectionHelper.OpenConnection(connectionStr)) { var balance = conn.ExecuteScalar(sumMonney); Console.WriteLine("sum money:" + balance); } count++; } } private static void DoDrawMoney() { Random random = new Random(); int money = random.Next(100); string userId = Thread.CurrentThread.Name; string selectSql = "select balance from user_balance where user_id=@UserId"; string updateSql = "update user_balance set balance=@Balance+@Money where user_id=@UserId"; string updateSql2 = "update user_balance set balance=@Balance-@Money where user_id<>@UserId"; using (MySqlConnection conn= MySqlConnectionHelper.OpenConnection(connectionStr)) { var balance = conn.ExecuteScalar(selectSql, new { UserId = userId }); if (balance != null) { conn.Execute(updateSql, new { Money = money, Balance=balance, UserId = userId }); conn.Execute(updateSql2, new { Money = money, Balance = balance, UserId = userId }); } } } private static void DrawMoney() { for (int i = 0; i < 100; i++) { DoDrawMoney(); } }

運行結果:

...

sum money:6000.00
sum money:6000.00
sum money:6025.00
sum money:5975.00
sum money:6056.00
sum money:5813.00
sum money:5943.00
sum money:5681.00
sum money:5455.00
sum money:5375.00

...

程序中有三條線程在跑:兩條支線程,一條主線程,主線程負責統計錢的總數,兩條支線程模擬兩個人賺錢,賺過來賺過去,哈哈哈,依據查詢成果可以看到,錢的總數原本是6000.00,但是之後開始減少。當然上面的異常也可以通過加事務解決,或者改變sql的實現方式balance=balance+money,不過這個不是我們討論的重點,不展開。

持續更新中...

C#線程--5.0之前時代(二)、線程的同步