JAVA:認識多線程

以前古老的DOS操作系統是單任務的,還沒有線程的概念,系統在每次只能做一件事情。比如你在copy東西的時候不能rename文件名。爲了提高系統的利用效率,採用批處理來批量執行任務。

現在的操作系統都是多任務操作系統,每個運行的任務就是操作系統所做的一件事情,比如你在聽歌的同時還在用MSN和好友聊天。聽歌和聊天就是兩個任務,這個兩個任務是“同時”進行的。一個任務一般對應一個進程,也可能包含好幾個進程。比如運行的MSN就對應一個MSN的進程,如果你用的是windows系統,你就可以在任務管理器中看到操作系統正在運行的進程信息。

一般來說,當運行一個應用程序的時候,就啓動了一個進程,當然有些會啓動多個進程。比如QQ,你用QQ等多個賬號的時候,打開任務管理器的時候就會發現打開一個賬戶就會有一個進程。啓動進程的時候,操作系統會爲進程分配資源,其中最主要的資源是內存空間,因爲程序是在內存中運行的。在進程中,有些程序流程塊是可以亂序執行的,並且這個代碼塊可以同時被多次執行。實際上,這樣的代碼塊就是線程體。線程是進程中亂序執行的代碼流程。當多個線程同時運行的時候,這樣的執行模式成爲併發執行,其中一半會滿足兩個條件,一個是可以亂序執行,一個是會被多次執行。

多線程的目的是爲了最大限度的利用CPU資源。

Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是通過線程來實現的。每用java命令啓動一個java應用程序,就會啓動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環境中,所有程序代碼的運行都是以線程來運行。

一般常見的Java應用程序都是單線程的。比如,用java命令運行一個最簡單的HelloWorld的Java應用程序時,就啓動了一個JVM進程,JVM找到程序程序的入口點main(),然後運行main()方法,這樣就產生了一個線程,這個線程稱之爲主線程。當然除了主線程之外肯定還會有另外的後臺線程,比如肯定會有的垃圾回收線程。當main方法結束後,主線程運行完成,當前臺線程,這裏也就是主線程,其他後臺線程也隨之結束。JVM進程也隨即退出 。

對於一個進程中的多個線程來說,多個線程共享進程的內存塊,當有新的線程產生的時候,操作系統不分配新的內存,而是讓新線程共享原有的進程塊的內存。因此,線程間的通信很容易,速度也很快。不同的進程因爲處於不同的內存塊,因此進程之間的通信相對困難,爲了保證其安全性和每個賬戶各自不同屬性,多個QQ賬號是以多個進程而非多個線程來運行。但線程共享進程塊的內存也帶來另外一個問題,當對個進程訪問同一個類調用相同的方法和讀寫相同變量時可能會破壞數據,導致異常的情況。

在Java程序中,JVM負責線程的調度。線程調度是值按照特定的機制爲多個線程分配CPU的使用權。

調度的模式有兩種:分時調度和搶佔式調度。分時調度是所有線程輪流獲得CPU使用權,並平均分配每個線程佔用CPU的時間;搶佔式調度是根據線程的優先級別來獲取CPU的使用權。JVM的線程調度模式採用了搶佔式模式。比如Main線程它的優先級就是5,你可以通過setPriority()函數來設置線程的優先級,從1到10,10優先級最高,1優先級最低,但不代表優先級高就一定先執行,誰先執行還是取決於誰先搶佔CPU的資源,較高的優先級只有有比較高的運行機會。JVM提供了10個線程優先級,但與常見的操作系統都不能很好的映射。如果希望程序能移植到各個操作系統中,應該僅僅使用Thread類有以下三個靜態常量作爲優先級,這樣能保證同樣的優先級採用了同樣的調度方式。

所謂的“併發執行”、“同時”其實都不是真正意義上的“同時”。用我們操作系統老師的話說就是,宏觀上並行,微觀上串行。雖然操作系統是多線程多任務的,但是對於CPU來說,在同一時刻內,它只能做一件事。在一個時鐘週期內,它就只能執行一條命令(特殊情況會有多條)。操作系統將進程線程進行管理,輪流(沒有固定的順序)分配每個進程很短的一段是時間(不一定是均分),然後在每個線程內部,程序代碼自己處理該進程內部線程的時間分配,多個線程之間相互的切換去執行,這個切換時間也是非常短的。因此多任務、多進程、多線程都是操作系統給人的一種宏觀感受,從微觀角度看,程序的運行是異步執行的。

部分概念:

主線程:JVM調用程序mian()所產生的線程。

當前線程:這個是容易混淆的概念。一般指通過Thread.currentThread()來獲取的進程。

後臺線程:指爲其他線程提供服務的線程,也稱爲守護線程。JVM的垃圾回收線程就是一個後臺線程。

前臺線程:是指接受後臺線程服務的線程,其實前臺後臺線程是聯繫在一起,就像傀儡和幕後操縱者一樣的關係。傀儡是前臺線程、幕後操縱者是後臺線程。由前臺線程創建的線程默認也是前臺線程。可以通過isDaemon()和setDaemon()方法來判斷和設置一個線程是否爲後臺線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章