java 多線程

最近開始研究多線程,記錄一下本身瞭解的知識,歡迎大神們拍板磚。java

進程、線程、併發執行數據庫

進程、線程、併發執行的概念:編程

  通常來講,當運行一個應用程序的時候,就啓動了一個進程,固然有些會啓動多個進程。啓動進程的時候,操做系統會爲進程分配資源,其中最主要的資源是內存空間,由於程序是在內存中運行的。多線程

在進程中,有些程序流程塊是能夠亂序執行的,而且這個代碼塊能夠同時被屢次執行。實際上,這樣的代碼塊就是線程體。線程是進程中亂序執行的代碼流程。當多個線程同時運行的時候,這樣的執行模式成爲併發執行。併發

舉個例子來講明進程和線程之間的區別和聯繫:學習

在此輸入圖片描述

這副圖是一個雙向多車道的道路圖,假如咱們把整條道路當作是一個「進程」的話,那麼圖中由白色虛線分隔開來的各個車道就是進程中的各個「線程」了。操作系統

1.這些線程(車道)共享了進程(道路)的公共資源(土地資源)。線程

2.這些線程(車道)必須依賴於進程(道路),也就是說,線程不能脫離於進程而存在(就像離開了道路,車道也就沒有意義了)。code

3.這些線程(車道)之間能夠併發執行(各個車道你走你的,我走個人),也能夠互相同步(某些車道在交通燈亮時禁止繼續前行或轉彎,必須等待其它車道的車輛通行完畢)。對象

4.這些線程(車道)之間依靠代碼邏輯(交通燈)來控制運行,一旦代碼邏輯控制有誤(死鎖,多個線程同時競爭惟一資源),那麼線程將陷入混亂,無序之中。

5.這些線程(車道)之間誰先運行是未知的,只有在線程恰好被分配到CPU時間片(交通燈變化)的那一刻才能知道。

JVM與多線程

Java編寫的程序都運行在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是經過線程來實現的。

每用java命令啓動一個java應用程序,就會啓動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它本身。在這個JVM環境中,全部程序代碼的運行都是以線程來運行的。JVM找到程序的入口點main(),而後運行main()方法,這樣就產生了一個線程,這個線程稱之爲主線程。當main方法結束後,主線程運行完成。JVM進程也隨即退出。

操做系統將進程線程進行管理,輪流(沒有固定的順序)分配每一個進程很短的一段時間(不必定是均分),而後在每一個進程內部,程序代碼本身處理該進程內部線程的時間分配,多個線程之間相互的切換去執行,這個切換時間也是很是短的。

Java語言對多線程的支持

Java語言對多線程的支持經過類Thread和接口Runnable來實現。這裏就很少說了。這裏重點強調兩個地方:

// 主線程其它代碼段
ThreadClass subThread = new ThreadClass();
subThread.start();
// 主線程其它代碼段
subThread.sleep(1000);

有人認爲如下的代碼在調用start()方法後,確定是先啓動子線程,而後主線程繼續執行。在調用sleep()方法後CPU什麼都不作,就在那裏等待休眠的時間結束。實際上這種理解是錯誤的。由於:

1.start()方法的調用後並非當即執行多線程代碼,而是使得該線程變爲可運行態(Runnable),何時運行是由操做系統決定的。

2.Thread.sleep()方法調用目的是不讓當前線程獨自霸佔該進程所獲取的CPU資源,以留出必定時間給其餘線程執行的機會(也就是靠內部本身協調)。

線程的狀態切換

因爲線程什麼時候執行是未知的,只有在CPU爲線程分配到時間片時,線程才能真正執行。在線程執行的過程當中,由可能會由於各類各樣的緣由而暫停(就像前面所舉的例子同樣:汽車只有在交通燈變綠的時候纔可以通行,並且在行駛的過程當中可能會出現塞車,等待其它車輛通行或轉彎的情況)。

這樣線程就有了「狀態」的概念,下面這副圖很好的反映了線程在不一樣狀況下的狀態變化。

在此輸入圖片描述

*新建狀態(New):*新建立了一個線程對象。

*就緒狀態(Runnable):*線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。

*運行狀態(Running):*就緒狀態的線程獲取了CPU,執行程序代碼。

*阻塞狀態(Blocked):*阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。阻塞的狀況分三種:

等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。

同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM把該線程放入鎖。

其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。

*死亡狀態(Dead):*線程執行完了或者因異常退出了run()方法,該線程結束生命週期。

Java中線程的調度API

Java中關於線程調度的API最主要的有下面幾個:

1.線程睡眠:Thread.sleep(long millis)方法

2.線程等待:Object類中的wait()方法

3,線程讓步:Thread.yield() 方法

4.線程加入:join()方法

5.線程喚醒:Object類中的notify()方法

關於這幾個方法的詳細應用,能夠參考SUN的API。這裏我重點總結一下這幾個方法的區別和使用。

sleep方法與wait方法的區別:

sleep方法是靜態方法,wait方法是非靜態方法。 sleep方法在時間到後會本身「醒來」,但wait不能,必須由其它線程經過notify(All)方法讓它「醒來」。 sleep方法一般用在不須要等待資源狀況下的阻塞,像等待線程、數據庫鏈接的狀況通常用wait。 sleep/wait與yeld方法的區別:調用sleep或wait方法後,線程即進入block狀態,而調用yeld方法後,線程進入runnable狀態。

wait與join方法的區別:

wait方法體現了線程之間的互斥關係,而join方法體現了線程之間的同步關係。 wait方法必須由其它線程來解鎖,而join方法不須要,只要被等待線程執行完畢,當前線程自動變爲就緒。 join方法的一個用途就是讓子線程在完成業務邏輯執行以前,主線程一直等待直到全部子線程執行完畢。 經過上面的介紹相信同窗們對java裏面的多線程已經有了基本的瞭解和認識。其實多線程編程並無你們想象中的那麼難,只要在實際的學習,工做當中不斷的加以練習和使用,相信你們很快就能掌握其中的奧妙,從而編寫出賞心悅目的java程序。

相關文章
相關標籤/搜索