最近使用了不少關於多線程的東西,現在有些時間了,就把多線程的知識總結一下。歡迎拍磚。
首先是建立一個線程的方式,大概有四種:
第一,繼承 Thread 類並重寫其中的 run 方法,然後執行個體化該類並調用 start 方法啟動線程;
第二,實現 Runnable 介面並重寫其中的 run 方法,然後將該類的執行個體作為 Thread 類的 target 建立一個 Thread 對象,調用 start 方法啟動線程;
第三,實現 Callable 介面並重寫其中的 call 方法,然後使用 FutureTask 封裝實現了 Callable 介面的類的對象,接下來將 FutureTask 類的執行個體作為 Thread 類的 target 建立線程並調用 start 方法啟動線程;
第四,調用 Executors 的靜態方法建立一個線程池,然後使用返回的 ExecutorService 對象的 submit 方法將 Runnable 或 Callable 的實作類別執行個體提交給線程池運行。
以上四種方式中,第一種方式是最基本的,第二種與第三種方式最終仍是建立了一個 Thread 類的對象,而最後一種方式通過線程池來實現效能的提高。
第一種方式由於所採取的是繼承 Thread 類,這也就導致了無法再繼承其他類,因此在靈活性上遜色於第二種方式,並且對於資源的共用而言,在子類中定義的執行個體屬性無法共用,安全固然安全,但也帶來了不便,甚至一定意義上失去了多線程的價值——共用資料。
第二種方式較常使用(^o^反正小菜我總是使用這種方式),重寫的 run 方法作為線程執行體當調用 start 方法後開始處於就緒狀態。這種方式由於使用的是實現 Runnable 介面,故而彌補了 Java 的單重繼承,但最後仍是作為 Thread 類的一個參數由 Thread 類的執行個體來執行線程,這也說明了在 Java 中是使用 Thread 類來代表線程,所有的線程對象都必須是 Thread 類或其子類的執行個體。
第三種方式的優勢是可以線上程執行完畢後得到一個傳回值,並且能夠聲明拋出異常(是對於 call 方法而言),而重寫 run 方法則不允許如此 "亂來"。
最後一種實現方式非常方便,而且提高了效能,在對於線程的使用非常頻繁的地方運用。
注意點:
1,不能妄圖直接調用 run 方法或 call 方法而啟動一個線程,這樣做的效果與調用普通方法是一樣的,最終是在主線程執行方法,而不會建立一個子線程。
2,可以使用 Thread 類的執行個體方法 getName 來取得一個線程的名字,當沒有通過 setName 方法設定線程名字(或沒有在建立線程時傳入一個代表線程名字的字串)時,預設情況下主線程名為 "main" ,子線程依次命名為 "Thread-0"、"Thread-1" 等,需要注意的是,在繼承自 Thread 類的子類中獲得當前線程的名字時可以直接使用 getName 方法,而在其他情形下要想獲得線程的名字,必須使用 "Thread.currentThread().getName()" 這種方式。
接下來是對於線程的控制,在 Java 中使用以下函數完成對線程的控制:
兩個 Thread 類中的靜態方法
① sleep ② yield
一個執行個體方法
① join
當然還有其他方法,比如 stop、suspend、resume 等,但一般不使用。而以上三個方法中,第一個方法可以讓當前處於運行狀態的線程進入阻塞狀態,從而讓其他的線程得以執行,該方法的參數指定處於阻塞狀態的時間,時間過後線程會重新回到就緒狀態等待下一次執行;而 yield 方法只會讓當前線程處於就緒狀態,這也就是說當前線程仍可能被繼續執行,當程式中的其餘線程優先順序低於當前線程時,調用該方法起不到預期效果,這時可以使用 setPriority 方法設定線程的優先順序,也就是說,yield 方法只會給優先順序等於或高於調用線程的線程以執行的機會。join
方法會使調用它的線程執行完之後再執行處於調用語句之後的代碼。
最後是安全執行緒問題。多線程使得資源的共用更為方便,尤其是採用後面三種建立線程的方法,同時也使得線程的安全性得不到保障。多條線程對於共用資料的隨機修改會造成嚴重的程式邏輯錯誤,這是因為一旦線程建立並啟動,各個線程之間的地位是完全相等的,不受建立它的線程影響。Java 中採用如下方式保證線程的安全性:
①同步代碼塊 ②同步方法 ③同步鎖
其中同步代碼塊可以使用任一對象作為同步監視器,而同步方法預設使用當前對象作為同步監視器,同步鎖則使得安全執行緒的操作更靈活。其實本質上這三者的思路都是相同的,都是使對於競爭資源的訪問遵循先加鎖才能訪問,使用結束就放鎖,以便其他線程獲得鎖進而訪問該資源。
當然多線程還有關於死結、通訊等內容,說來慚愧,對此不熟悉,就不在各位關公面前耍大刀了。總之,多線程使得程式的結構更加理想,是程式中不可缺少的部分。