進程和線程
說到多線程,不妨先談一談進程的概念。在百度百科中對進程的解釋如下:
其實簡單理解程序的實體,就是我們操作系統運行的一個基本單元
比如我們系統運行着的微信這個聊天軟件,就可以理解爲一個進程。
那麼線程又是什麼呢?
線程可以理解爲進程中獨立運行的子任務就是一個線程,比如好友視頻線程、下載文件線程、傳輸數據線程、微信聊天線程等。
那多線程的好處又是什麼呢?
1、發揮多核CPU的能力
現在,多處理器系統正日益盛行,並且價格不斷降低,即時在低端服務器和中斷桌面系統中,通常也會採用多個處理器,這種趨勢還在進一步加快,因爲通過提高時鐘頻率來提升性能已變得越來越困難,處理器生產廠商都開始轉而在單個芯片上放置多個處理器核。試想,如果只有單個線程,雙核處理器系統上程序只能使用一半的CPU資源,擁有100個處理器的系統上將有99%的資源無法使用。多線程程序則可以同時在多個處理器上執行,如果設計正確,多線程程序可以通過提高處理器資源的利用率來提升系統吞吐率。
2、提高單處理器的吞吐率
如果程序是單線程的,那麼當程序等待某個同步I/O操作完成時,處理器將處於空閒狀態。而在多線程程序中,
如果一個線程在等待I/O操作完成,另一個線程可以繼續運行,使得程序能在I/O阻塞期間繼續運行。
注意:多線程是異步的,所以千萬不要把代碼的順序當成線程執行的順序,線程被調用的時機是隨機的。
java中使用多線程
1:繼承Thread
public class Mythread extends Thread { public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "在運行!"); } } }
@Test public void test1() { // 繼承Thread,重寫父類的run()方法。 Mythread mt0 = new Mythread(); mt0.start(); for (int i = 0; i < 5; i++) { // Thread.currentThread():返回代碼段正在被哪個線程調用的信息 System.out.println(Thread.currentThread().getName() + "在運行!"); } }
運行結果:
Thread-0在運行! Thread-0在運行! Thread-0在運行! Thread-0在運行! Thread-0在運行! main在運行! main在運行! main在運行! main在運行! main在運行!
2:實現Runnable接口
public class Mythread2 implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "在運行!"); } } }
@Test public void test2() { // 實現Runnable接口。和繼承自Thread類差不多,不過實現Runnable後,還是要通過一個Thread來啓動: Mythread2 mt0 = new Mythread2(); new Thread(mt0).start(); for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "在運行!"); } }
運行結果:
Thread-0在運行! Thread-0在運行! Thread-0在運行! Thread-0在運行! Thread-0在運行! main在運行! main在運行! main在運行! main在運行! main在運行!
其實Thread類也是實現的Runnable接口。兩種實現方式對比的關鍵就在於extends和implements的對比,當然是後者好。
因爲繼承只能單繼承,實現可以多實現,而且實現的方式對比繼承的方式,也有利於減小程序之間的耦合。
因此,多線程的實現幾乎都是使用的Runnable接口的方式。不過,後面的文章,爲了簡單,就用繼承Thread類的方式了。
線程狀態
虛擬機中的線程狀態有六種,定義在Thread.State中:
1、新建狀態NEW
new了但是沒有啓動的線程的狀態。比如"Thread t = new Thread()",t就是一個處於NEW狀態的線程
2、可運行狀態RUNNABLE
new出來線程,調用start()方法即處於RUNNABLE狀態了。處於RUNNABLE狀態的線程可能正在Java虛擬機中運行,也可能正在等待處理器的資源,因爲一個線程必須獲得CPU的資源後,纔可以運行其run()方法中的內容,否則排隊等待
3、阻塞BLOCKED
如果某一線程正在等待監視器鎖,以便進入一個同步的塊/方法,那麼這個線程的狀態就是阻塞BLOCKED
4、等待WAITING
某一線程因爲調用不帶超時的Object的wait()方法、不帶超時的Thread的join()方法、LockSupport的park()方法,就會處於等待WAITING狀態
5、超時等待TIMED_WAITING
某一線程因爲調用帶有指定正等待時間的Object的wait()方法、Thread的join()方法、Thread的sleep()方法、LockSupport的parkNanos()方法、LockSupport的parkUntil()方法,就會處於超時等待TIMED_WAITING狀態
6、終止狀態TERMINATED
線程調用終止或者run()方法執行結束後,線程即處於終止狀態。處於終止狀態的線程不具備繼續運行的能力
參考文獻
1:《Java併發編程的藝術》
2:《Java多線程編程核心技術》