日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多线程(6)线程同步

發(fā)布時(shí)間:2024/1/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多线程(6)线程同步 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
使用多線程很容易,但是如果多個(gè)線程同時(shí)訪問一個(gè)共享資源時(shí)而不加以控制,就會(huì)導(dǎo)致數(shù)據(jù)損壞。所以多線程并發(fā)時(shí),必須要考慮線程同步(或稱線程安全)的問題。?

什么是線程同步

多個(gè)線程同時(shí)訪問共享資源時(shí),使多個(gè)線程順序(串行)訪問共享資源的機(jī)制。 注意: 1,共享資源,比如全局變量和靜態(tài)變量。 2,訪問,一般指寫操作,讀操作無需考慮線程同步。 3,串行,指當(dāng)一個(gè)線程正在訪問共享資源時(shí),其它線程等待,直到該線程釋放鎖。

線程同步帶來哪些問題

如果能保證多個(gè)線程不會(huì)同時(shí)訪問共享資源,那么就不需要考慮線程同步。 雖然線程同步能保證多線程同時(shí)訪問共享數(shù)據(jù)時(shí)線程安全,但是同時(shí)也會(huì)帶來以下問題: 1,使用起來繁瑣,因?yàn)楸仨氄页龃a中所有可能由多個(gè)線程同時(shí)訪問的共享數(shù)據(jù),并且要用額外的代碼將這些代碼包圍起來,獲取和釋放一個(gè)線程同步鎖,而一旦有一處忘記用鎖包圍,共享數(shù)據(jù)就會(huì)被損壞。 2,損害性能,因?yàn)楂@取和釋放一個(gè)鎖是需要時(shí)間的。 3,可能會(huì)造成更多的線程被創(chuàng)建,由于線程同步鎖一次只允許一個(gè)線程訪問共享資源,當(dāng)線程池線程試圖獲取一個(gè)暫時(shí)無法獲取的鎖時(shí),線程池就會(huì)創(chuàng)建一個(gè)新的線程。 所以,要從設(shè)計(jì)上盡可能地避免線程同步,實(shí)在不能避免的再考慮線程同步。

線程同步的常用解決方案

1,鎖

包括lock關(guān)鍵字和Monitor類型。 使用lock關(guān)鍵字實(shí)現(xiàn):

?

1 /// <summary> 2 /// 線程同步計(jì)算器 3 /// </summary> 4 public class SyncCounter : CounterBase 5 { 6 /// <summary> 7 /// 全局變量 8 /// </summary> 9 public int Result = 0; 10 11 private static readonly object lockObj = new object(); 12 13 public override void Increase() 14 { 15 lock (lockObj) 16 { 17 Result++; 18 } 19 } 20 21 public override void Decrease() 22 { 23 lock (lockObj) 24 { 25 Result--; 26 } 27 } 28 } View Code 需要注意的是: 1,lock鎖定的對象必須是引用類型,不能是值類型。因?yàn)橹殿愋蛡魅霑?huì)發(fā)生裝箱,這樣每次lock的將是一個(gè)不同的對象,就沒有辦法實(shí)現(xiàn)多線程同步了。 2,避免使用public類型的對象,這樣很容易導(dǎo)致死鎖。因?yàn)槠渌a也有可能鎖定該對象。 3,避免鎖定字符串,因?yàn)樽址畷?huì)被CLR暫留(也就是說兩個(gè)變量的字符串內(nèi)容相同,.net會(huì)把暫留的字符串對象分配給變量),導(dǎo)致應(yīng)用程序中鎖定的是同一個(gè)對象,造成死鎖。 使用Monitor實(shí)現(xiàn): 1 /// <summary> 2 /// 線程同步計(jì)算器 3 /// </summary> 4 public class SyncCounter : CounterBase 5 { 6 /// <summary> 7 /// 全局變量 8 /// </summary> 9 public int Result = 0; 10 11 private static readonly object lockObj = new object(); 12 13 public override void Increase() 14 { 15 Monitor.Enter(lockObj); 16 try 17 { 18 Result++; 19 } 20 finally 21 { 22 Monitor.Exit(lockObj); 23 } 24 } 25 26 public override void Decrease() 27 { 28 Monitor.Enter(lockObj); 29 try 30 { 31 Result--; 32 } 33 finally 34 { 35 Monitor.Exit(lockObj); 36 } 37 } 38 } View Code

完整代碼:

1 namespace ConsoleApplication28 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //同時(shí)發(fā)起3個(gè)異步線程 8 Console.WriteLine("普通(非線程同步)計(jì)算器測試..."); 9 var normalCounter = new NormalCounter(); 10 var tasks = new List<Task>(); 11 var task1 = Task.Factory.StartNew(() => 12 { 13 TestCounter(normalCounter); 14 }); 15 tasks.Add(task1); 16 17 var task2 = Task.Factory.StartNew(() => 18 { 19 TestCounter(normalCounter); 20 }); 21 tasks.Add(task2); 22 23 var task3 = Task.Factory.StartNew(() => 24 { 25 TestCounter(normalCounter); 26 }); 27 tasks.Add(task3); 28 29 30 Task.WaitAll(tasks.ToArray()); 31 Console.WriteLine("NormalCounter.Result:" + normalCounter.Result); 32 Console.WriteLine("*******************************************"); 33 34 Console.WriteLine("線程同步計(jì)算器測試..."); 35 var syncCounter = new SyncCounter(); 36 var tasks1 = new List<Task>(); 37 task1 = Task.Factory.StartNew(() => 38 { 39 TestCounter(syncCounter); 40 }); 41 tasks1.Add(task1); 42 43 task2 = Task.Factory.StartNew(() => 44 { 45 TestCounter(syncCounter); 46 }); 47 tasks1.Add(task2); 48 49 task3 = Task.Factory.StartNew(() => 50 { 51 TestCounter(syncCounter); 52 }); 53 tasks1.Add(task3); 54 55 Task.WaitAll(tasks1.ToArray()); 56 Console.WriteLine("SyncCounter.Result:" + syncCounter.Result); 57 58 Console.ReadKey(); 59 } 60 61 /// <summary> 62 /// 63 /// </summary> 64 /// <param name="counter"></param> 65 static void TestCounter(CounterBase counter) 66 { 67 //100000次加減 68 for (int i = 0; i < 100000; i++) 69 { 70 counter.Increase(); 71 counter.Decrease(); 72 } 73 } 74 } 75 76 /// <summary> 77 /// 計(jì)算器基類 78 /// </summary> 79 public abstract class CounterBase 80 { 81 /// <summary> 82 /// 83 /// </summary> 84 public abstract void Increase(); 85 86 /// <summary> 87 /// 88 /// </summary> 89 public abstract void Decrease(); 90 } 91 92 /// <summary> 93 /// 普通計(jì)算器 94 /// </summary> 95 public class NormalCounter : CounterBase 96 { 97 /// <summary> 98 /// 全局變量 99 /// </summary> 100 public int Result = 0; 101 102 public override void Increase() 103 { 104 Result++; 105 } 106 107 public override void Decrease() 108 { 109 Result--; 110 } 111 112 } 113 114 /// <summary> 115 /// 線程同步計(jì)算器 116 /// </summary> 117 public class SyncCounter : CounterBase 118 { 119 /// <summary> 120 /// 全局變量 121 /// </summary> 122 public int Result = 0; 123 124 private static readonly object lockObj = new object(); 125 126 public override void Increase() 127 { 128 lock (lockObj) 129 { 130 Result++; 131 } 132 } 133 134 public override void Decrease() 135 { 136 lock (lockObj) 137 { 138 Result--; 139 } 140 } 141 } 142 } View Code

??

lock關(guān)鍵字揭密:

通過查看lock關(guān)鍵字生成的IL代碼,如下圖:

從上圖可以得出以下結(jié)論:

lock關(guān)鍵字內(nèi)部就是使用Monitor類(或者說lock關(guān)鍵字是Monitor的語法糖),使用lock關(guān)鍵字比直接使用Monitor更好,原因有二。

1,lock語法更簡潔。

2,lock確保了即使代碼拋出異常,也可以釋放鎖,因?yàn)樵趂inally中調(diào)用了Monitor.Exit方法。?

2,信號同步

信號同步機(jī)制中涉及的類型都繼承自抽象類WaitHandle,這些類型有EventWaitHandle(類型化為AutoResetEvent、ManualResetEvent)和Semaphore以及Mutex。關(guān)系如下圖。

?

下面是使用信號同步機(jī)制的一個(gè)簡單的例子,如下代碼:

1 namespace WindowsFormsApplication1 2 { 3 public partial class Form1 : Form 4 { 5 //信號 6 AutoResetEvent autoResetEvent = new AutoResetEvent(false); 7 8 public Form1() 9 { 10 InitializeComponent(); 11 12 CheckForIllegalCrossThreadCalls = false; 13 } 14 15 /// <summary> 16 /// 開始 17 /// </summary> 18 /// <param name="sender"></param> 19 /// <param name="e"></param> 20 private void button1_Click(object sender, EventArgs e) 21 { 22 Task.Factory.StartNew(() => 23 { 24 this.richTextBox1.Text+="線程啟動(dòng)..." + Environment.NewLine; 25 this.richTextBox1.Text += "開始處理一些實(shí)際的工作" + Environment.NewLine; 26 Thread.Sleep(3000); 27 28 this.richTextBox1.Text += "我開始等待別的線程給我信號,才愿意繼續(xù)下去" + Environment.NewLine; 29 autoResetEvent.WaitOne(); 30 this.richTextBox1.Text += "我繼續(xù)做一些工作,然后結(jié)束了!"; 31 }); 32 } 33 34 /// <summary> 35 /// 信號同步 36 /// </summary> 37 /// <param name="sender"></param> 38 /// <param name="e"></param> 39 private void button2_Click(object sender, EventArgs e) 40 { 41 //給在autoResetEvent上等待的線程一個(gè)信號 42 autoResetEvent.Set(); 43 } 44 } 45 } View Code

運(yùn)行效果:

1,線程阻塞,等待信號。

2,主線程發(fā)送信號,讓線程繼續(xù)執(zhí)行。

3,線程安全的集合類

我們也可以通過使用.net提供的線程安全的集合類來保證線程安全。在命名空間:System.Collections.Concurrent下。 主要包括:
  • ConcurrentQueue 線程安全版本的Queue【常用】
  • ConcurrentStack線程安全版本的Stack
  • ConcurrentBag線程安全的對象集合
  • ConcurrentDictionary線程安全的Dictionary【常用】

總結(jié)

以上是生活随笔為你收集整理的多线程(6)线程同步的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产第6页| 日韩中文字幕视频 | 青青草伊人网 | 欧美精品99久久 | 懂色视频在线观看 | 精品毛片 | 男人桶女人桶爽30分钟 | 亚洲AV无码成人精品区明星换面 | 欧美精品综合 | 亚洲成人精品久久久 | 欧美日韩一卡二卡三卡 | 男人天堂一区二区 | 国产一区二区在线视频 | 青青草国产在线观看 | 边啃奶头边躁狠狠躁 | 日本免费不卡视频 | 特级西西www444人体聚色 | 午夜67194| 免费在线观看日韩 | 欧美日韩在线视频一区二区三区 | 亚洲最大在线观看 | 精品三级在线 | 成人动漫在线免费观看 | 精品综合久久久久 | 福利在线小视频 | 一级特黄特色的免费大片视频 | 亚洲1级片 | 特级精品毛片免费观看 | 97在线观视频免费观看 | 操操操操操操操 | 黄色片网站视频 | 亚洲欧洲日韩 | 天天干天天摸天天操 | 竹菊影视日韩一区二区 | 精品久久久久一区二区国产 | 国产精品99精品无码视 | 巨胸喷奶水www久久久免费动漫 | 亚洲成人福利在线 | 美女自拍偷拍 | 亚洲精品国产福利 | 狠狠夜夜 | 狠狠插狠狠干 | 久久久18| 久久久成人精品一区二区三区 | a天堂资源在线观看 | 中文字幕一区二区三区视频 | 九九热精品视频 | 五月激情av | 好男人www社区在线视频夜恋 | 久久国产精品无码一区二区 | 日韩电影一区二区三区 | 污视频免费在线 | 亚洲妇熟xx妇色黄蜜桃 | 国产毛片儿 | av在线免费观看不卡 | 国产精品男女视频 | av片久久| 91精品国产高清91久久久久久 | 一区二区自拍偷拍 | 伊人狼人久久 | 人妻在卧室被老板疯狂进入 | 欧美在线观看www | 色网站入口 | 国产福利精品在线观看 | 成人国产在线 | 大战熟女丰满人妻av | 免费国产小视频 | 成人视频在线观看 | 人妻无码一区二区三区四区 | 在线观看视频99 | 欧美成人看片黄a免费看 | 国产一级久久 | aa成人 | 日韩a在线观看 | 打开免费观看视频在线播放 | 国产日韩欧美专区 | 国产精品美女一区二区三区 | 美女视频一区二区三区 | 成人黄色小说视频 | 国产在线不卡视频 | 亚洲一区二区蜜桃 | 在线亚洲不卡 | 亚一区二区 | 午夜国产一区二区三区 | a在线免费观看 | 神马午夜伦理影院 | 亚洲涩视频 | 精品国产一区二区三区噜噜噜 | 国产免费av一区二区三区 | 91香草视频 | 国产老头和老头xxxx× | 校园伸入裙底揉捏1v1h | 久久丝袜美腿 | 欧美色影院 | 欧美剧场 | 一二三区在线 | 台湾佬成人中文网222vvv | 97国产在线播放 | 又黄又骚又爽 |