0. 參考文檔
1. 描述線程與進程的區別?
線程(Thread)與進程(Process)二者都定義了某種邊界,不同的是進程定義的是應用程序與應用程序之間的邊界,不同的進程之間不能共享代碼和數據空間,而線程定義的是代碼執行堆棧和執行上下文的邊界
一個進程可以包括若干個線程,同時創建多個線程來完成某項任務,便是多線程
2. 什么是互斥?
當多個線程訪問同一個全局變量,或者同一個資源(比如打印機)的時候,需要進行線程間的互斥操作來保證訪問的安全性
3. Task狀態機的實現和工作機制是什么?
CPS全稱是Continuation Passing Style,在.NET中,它會自動編譯為:
- 將所有引用的局部變量做成閉包,放到一個隱藏的狀態機的類中
- 將所有的await展開成一個狀態號,有幾個await就有幾個狀態號
- 每次執行完一個狀態,都重復回調狀態機的MoveNext方法,同時指定下一個狀態號
- MoveNext方法還需處理線程和異常等問題
4. await的作用和原理,並說明和GetResult()有什么區別?
從狀態機的角度出發,await的本質是調用Task.GetAwaiter()的UnsafeOnCompleted(Action)回調,並指定下一個狀態號
從多線程的角度出發,如果await的Task需要在新的線程上執行,該狀態機的MoveNext()方法會立即返回,此時,主線程被釋放出來了,然后在UnsafeOnCompleted回調的action指定的線程上下文中繼續MoveNext()和下一個狀態的代碼
而相比之下,GetResult()就是在當前線程上立即等待Task的完成,在Task完成前,當前線程不會釋放
注意:Task也可能不一定在新的線程上執行,此時用GetResult()或者await就只有會不會創建狀態機的區別了
5. Task和Thread有區別嗎?
Task和Thread都能創建用多線程的方式執行代碼,但它們有較大的區別
Task較新,發布於.NET 4.5,能結合新的async/await代碼模型寫代碼,它不止能創建新線程,還能使用線程池(默認)、單線程等方式編程,在UI編程領域,Task還能自動返回UI線程上下文,還提供了許多便利API以管理多個Task
6. 多線程有什么用?
發揮多核CPU的優勢,防止阻塞
7. 說說常用的鎖,lock是一種什么樣的鎖?
常用的如 SemaphoreSlim、ManualResetEventSlim、Monitor、ReadWriteLockSlim
lock是一個混合鎖,其實質是 Monitor
8. lock為什么要鎖定一個參數(可否為值類型?)參數有什么要求?
lock的鎖對象要求為一個引用類型,可以鎖定值類型,但值類型會被裝箱,每次裝箱后的對象都不一樣,會導致鎖定無效
對於lock鎖,鎖定的這個對象參數才是關鍵,這個參數的同步索引塊指針會指向一個真正的鎖(同步塊),這個鎖(同步塊)會被復用
9. 多線程和異步的區別和聯系?
多線程是實現異步的主要方式之一,異步並不等同於多線程
實現異步的方式還有很多,比如利用硬件的特性、使用進程或纖程等
在.NET中就有很多的異步編程支持,比如很多地方都有Begin、End 的方法,就是一種異步編程支持,內部有些是利用多線程,有些是利用硬件的特性來實現的異步編程
10. 線程池的優點和不足?
優點:減小線程創建和銷毀的開銷,可以復用線程,也從而減少了線程上下文切換的性能損失,在GC回收時,較少的線程更有利於GC的回收效率
缺點:線程池無法對一個線程有更多的精確的控制,如了解其運行狀態等;不能設置線程的優先級;加入到線程池的任務(方法)不能有返回值;對於需要長期運行的任務就不適合線程池
11. Mutex和lock有什么不同?一般用哪一種比較好?
Mutex是一個基於內核模式的互斥鎖,支持鎖的遞歸調用
Lock是一個混合鎖,一般建議使用Lock更好,因為lock的性能更好
12. 如何實現線程間通信?
最簡單的就是定義靜態變量,然后在各個線程之間通過lock來訪問或修改變量
其次是利用線程上下文