【线程呓语】与线程相关的一些概念
上一篇文章已經介紹了,線程是對CPU的模擬和抽象,因為一臺機器只有一個CPU,又要執行多個應用的代碼,為了讓上層應用不考慮這些細節,而使用線程這么個東西抽象一下,這樣讓上層應用覺得整個CPU都是它的。但CPU畢竟只有一個(或是有限的),那么就必定存在線程的切換。這也就涉及線程的狀態轉換:
主意這里的箭頭有雙向的,有單向的。
線程在運行時可能由于需要某種資源而暫時停止運行,這稱之為阻塞,當需要的資源得到滿足時線程的狀態會變成就緒,如果這個時候正好有CPU空閑或者正好線程調度到這個線程上,那么該線程就會馬上執行。線程在運行時還有可能因為自己的時間片用完了,線程調度程序安排別的線程執行(上下文切換),而從運行狀態變成就緒狀態。就緒狀態也可以稍后調度為運行狀態。線程調度的算法有很多種,這在操作系統領域有很多文獻專門來描述這個。
死鎖(deadlock)
在寫多線程相關的書籍或者文章中,恐怕死鎖這個詞出現的頻率最高。那死鎖到底是一個什么意思呢?
為了解釋這個概念,我們假設有兩個線程T1和T2,有兩個資源R1和R2。在某一時刻,T1擁有R1,T2擁有R2。但是這兩個線程貪得無厭,T1還需要R2才能運行所以阻塞了,而T2需要R1才能運行所以也阻塞了。所以這兩個線程總是不斷地嘗試獲取永遠也得不到的東西互不相讓,這種狀態除非有外力的介入,不然不會打破。這就是死鎖。死鎖的危害性非常大,有可能造成整個系統的宕機。
我們來看下面這段程序,來演示一下如何弄出個死鎖出來(該程序僅僅為了演示目的,實際中不要如此編碼):
1: using System; 2: using System.Threading; 3: namespace DeadLock 4: { 5: class Program 6: { 7: static void Main(string[] args) 8: { 9: Test t = new Test(); 10: Thread t1 = new Thread(t.test1); 11: Thread t2 = new Thread(t.test2); 12:? 13: t1.Start(); 14: t2.Start(); 15:? 16: Console.ReadLine(); 17:? 18: } 19: } 20:? 21: public class Test 22: { 23: private object resource1 = new object(); 24: private object resource2 = new object(); 25:? 26: public void test1() 27: { 28:? 29: Console.WriteLine(string.Format("test1:Thread{0} try to get resouce1", Thread.CurrentThread.ManagedThreadId.ToString())); 30: lock (resource1) 31: { 32: Console.WriteLine(string.Format("test1:Thread{0} got resouce1", Thread.CurrentThread.ManagedThreadId.ToString())); 33: Thread.Sleep(500); 34: Console.WriteLine(string.Format("test1:Thread{0} try to get resouce2", Thread.CurrentThread.ManagedThreadId.ToString())); 35: lock (resource2) 36: { 37: Console.WriteLine(string.Format("test1:Thread{0} got resouce2", Thread.CurrentThread.ManagedThreadId.ToString())); 38: } 39: } 40: } 41:? 42: public void test2() 43: { 44: Console.WriteLine(string.Format("test2:Thread{0} try to get resouce2", Thread.CurrentThread.ManagedThreadId.ToString())); 45: lock (resource2) 46: { 47: Console.WriteLine(string.Format("test2:Thread{0} got resouce2", Thread.CurrentThread.ManagedThreadId.ToString())); 48: Thread.Sleep(500); 49: Console.WriteLine(string.Format("test2:Thread{0} try to get resouce1", Thread.CurrentThread.ManagedThreadId.ToString())); 50: lock (resource1) 51: { 52: Console.WriteLine(string.Format("test2:Thread{0} got resouce1", Thread.CurrentThread.ManagedThreadId.ToString())); 53: } 54: } 55: } 56: } 57: }thread1獲取resource1后等待一會兒,讓thread2獲取到resource2,然后thread1“咬住”resource1死死不放,還去獲取resource2,而thread2“咬住”resource2死死不放,去獲取resource1,這樣thread1和thread就像抱團一樣了。
死鎖形成的必要條件:
互斥條件:resource1和resource2只能被一個線程擁有
占有和等待條件:已經得到resource1的thread1可以再請求resource2,thread2也可以在獲取到resource2后再獲取resource1
不可搶占條件:已經分配給一個線程的資源不能強制性地被搶占(thread1已經得到了resource1,不能強制地剝奪它,除非thread1自己釋放resource1,在這里就是退出lock塊)
循環等待條件:死鎖發生時,系統中肯定有兩個或兩個以上的線程組成一條環路,該環路中的每個線程都等待著下一個線程已經占有的資源。
與死鎖相近的一個概念是活鎖,或稱之為饑餓
活鎖(livelock)
說的就是某個線程或進程因為某些原因總是得不到自己需要的資源。假如現在排隊買飯,飯堂規定年齡小的和年齡老的可以優先買飯,站在隊伍的前面,如果總是有源源不斷的人加進來,且總是 比你年齡小或年齡老,你就總是排在隊伍的后頭,最后饑餓而死~~
還有一個常見的情況是,編程時為了提高效率,常常將寫操作和讀操作分開,比如多個線程可以同時讀某一資源,但只要有一個線程寫那么其他線程就不能讀也不能寫了,那么如果現在有很多線程在讀資源A,而有一個線程來寫,這樣就會造成總是有線程在讀,而寫線程卻插不上去。
線程安全(thread safety)
在一些框架API文檔中總是會出現這么一個句子:該接口是線程安全的。那么線程安全到底是什么意思呢?
意思就是說這個接口是否能在多線程環境下安全的調用。比如該接口可能會修改一些共享的數據,而又沒有對這些共享數據加鎖,那么就不能安全地在多線程環境下使用了。
轉載于:https://www.cnblogs.com/yuyijq/archive/2011/01/18/1938678.html
總結
以上是生活随笔為你收集整理的【线程呓语】与线程相关的一些概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魔兽世界怀旧服附魔图纸怎么得?最全附魔图
- 下一篇: 个人可以去银行借钱吗