您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關怎么進行Java多線程概念和使用原理的分析,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
首選了解一下什么是進程和線程的概念?
進程是運行中的應用程序,每個進程都有自己獨立的一塊內存空間,一個進程可以啟動多個線程,而線程是指進程中的一個執行流程,也可以理解成一段代碼。比如java.exe進程中可以運行很多線程,線程永遠屬于某個進程,進程中的多個線程共享進程的內存。
在Java中為了創建一個新的線程,必須指明線程所要執行的代碼。通過Java提供的類java.lang.Thread來方便多線程編程,這個類提供了大量的方法來方便我們控制自己的各個線程。那么如何通過Java線程來執行的代碼呢?
Thread類中提供了一個最重要的run()方法,它被Thread類的start()方法調用,提供給我們線程要執行的代碼。為了執行我們自己的代碼只需要重寫該方法即可。
方式一:繼承Thread類,重寫run()方法
創建Thread類的子類繼承該對象重寫run()方法,具體代碼實例如下:
上述方法簡單明了符合大家的寫作習慣,但是有一個很大的缺點,那就是如果我們的類已經是其他類的子類,就無法再繼承Thread類,此時如果不想創建一個新的類,應該怎么辦呢?
我們只能將我們的方法作為參數傳遞給Thread類的實例,類似回調函數,但是Java是沒有指針的,我們只能傳遞一個包含該方法的實例。Java使用接口java.lang.Runnable解決這個問題。
Runnable接口只有一個run()方法,聲明類實現Runnable接口并提供這一方法,將線程代碼寫入這個方法完成任務,但是Runnable接口并沒有任何對線程的支持,因此必須創建Thread類的實例,通過Thread類的構造函數完成。
方式二:實現Runnable接口,代碼實例如下:
使用Runnable接口來實現多線程使得我們能夠在一個類中包容所有的代碼,有利于封裝。缺點在于只能使用一套代碼,若想創建多個線程并使各個線程執行不同的代碼,則仍必須額外創建類,如果這樣的話,在大多數情況下也許還不如直接用多個類分別繼承Thread來得方便。綜上所述比較兩種實現多線程的方法各有千秋,大家可以靈活運用。
下面和大家分析一下多線程在使用中的一些常見問題。
一:線程可以劃分為七種狀態(有些人認為只有五種,將鎖池和等待池看成阻塞狀態的特殊情況,這種認知也是正確的但是鎖池和等待池單獨分離有利于對程序的理解)。
1.初始狀態,線程創建,線程對象調用start()方法
2.可運行狀態,也就是等待CPU資源,等待運行的狀態
3.運行狀態,獲得了CPU資源,正在運行狀態
4.阻塞狀態,也就是讓出CPU資源,進入一種等待狀態,而且不是可運行狀態,有三種情況會進入阻塞狀態。
1)如等待輸入(輸入設備進行處理,而CUP不處理),則放入阻塞,直到輸入完畢,阻塞結束后會進入可運行狀態。
2)線程休眠,線程對象調用sleep()方法,阻塞結束后會進入可運行狀態。
3)線程對象 2 調用線程對象 1 的join()方法,那么線程對象 2 進入阻塞狀態,直到線程對象 1 中止。
5.中止狀態,也就是執行結束
6.鎖池狀態
7.等待隊列
二:線程優先級
線程的優先級代表該線程的重要程度,當有多個線程同時處于可執行狀態并等待獲得CPU時間時,線程調度系統根據各個線程的優先級來決定給誰分配CPU時間,優先級高的線程有更大的機會獲得CPU時間,優先級低的線程獲取CPU時間幾率比較小。調用Thread類的getPriority()和setPriority()方法來存取線程的優先級,線程的優先級界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,缺省是5(NORM_PRIORITY)。
三:線程同步
由于同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突嚴重的問題。Java語言提供了專門的機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。由于我們可以通過private關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是synchronized關鍵字,它包括兩種用法:synchronized方法和synchronized塊。
1. 通過在方法聲明中加入synchronized關鍵字來聲明synchronized方法。如:public synchronized void accessVal(int newVal);synchronized方法控制對類成員變量的訪問:每個類實例對應一把鎖,每個synchronized方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執行狀態。
這種機制確保了同一時刻對于每一個類實例,其所有聲明為synchronized的成員函數中至多只有一個處于可執行狀態,從而有效避免了類成員變量的訪問沖突。在Java中不單單只有類實例,每一個類也是對應一把鎖,這樣我們也可將類的靜態成員函數聲明為synchronized,以控制其對類的靜態成員變量的訪問。
synchronized方法的缺陷:若將一個大的方法聲明為synchronized將會大大影響效率,典型地,若將線程類的run()方法聲明為synchronized,由于在線程的整個生命期內它一直在運行,因此將導致它對本類任何synchronized方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變量的代碼放到專門的方法中將其聲明為synchronized,并在主方法中調用來解決這一問題,但是Java為我們提供了更好的解決辦法,那就是synchronized塊。
2. 通過synchronized關鍵字來聲明synchronized塊,語法如下:
synchronized(syncObject) {
//允許訪問控制的代碼
}
synchronized塊是一個代碼塊,其中的代碼必須獲得對象syncObject(類實例或類)的鎖方能執行。由于可以針對任意代碼塊且可任意指定上鎖的對象,因此靈活性比較高。
四:線程阻塞
為了解決對共享存儲區的訪問沖突,Java引入了同步機制。阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),Java提供了大量方法來支持阻塞,下面逐一進行分析:
1. sleep()方法:sleep()允許指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU時間,指定的時間一過,線程重新進入可執行狀態。
2. suspend()和resume()方法:兩個方法配合使用,suspend()使得線程進入阻塞狀態不會自動恢復,必須其對應的resume()被調用,才能使得線程重新進入可執行狀態。
3. yield()方法:yield()使得線程放棄當前分得的CPU時間,但是不使線程阻塞,即線程仍處于可執行狀態,隨時可能再次分得CPU時間。調用yield()的效果等價于調度程序認為該線程已執行了足夠的時間從而轉到另一個線程。
4. wait()和 notify()方法:兩個方法配合使用,wait()使得線程進入阻塞狀態,它有兩種形式,一種允許指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的notify()被調用或者超出指定時間時線程重新進入可執行狀態,后者則必須對應的notify()被調用。注意的是1 2 3 步驟阻塞時都不會釋放占用的鎖而這一對方法則會釋放占用的鎖。
關于 wait()和 notify()方法最后再說明兩點:
1)調用notify()方法導致解除阻塞的線程是因為調用該對象的wait()方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。
2)除了notify(),還有一個notifyAll()方法也可起到類似作用,唯一的區別在于,調用notifyAll()方法將把因為調用該對象的wait()方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執行狀態。
說到阻塞就不能不說一說死鎖的概念,略一分析就能發現suspend()方法和不指定超時期限的wait()方法的調用都可能產生死鎖。遺憾的是Java并不在語言級別上支持死鎖的避免,因此我們在編程中必須小心地避免死鎖。
五:守護線程
守護線程是一類特殊的線程,它和普通線程的區別在于它并不是應用程序的核心部分,當一個應用程序的所有非守護線程終止運行時,即使仍然有守護線程在運行,應用程序也將終止,相反只要有一個非守護線程在運行應用程序就不會終止。守護線程一般被用于在后臺為其它線程提供服務。可以通過調用isDaemon()方法來判斷一個線程是否是守護線程,可以調用setDaemon()方法來將一個線程設為守護線程。
六:線程組
線程組是Java特有的一個概念,在Java中線程組是ThreadGroup類的對象,每個線程都隸屬于唯一一個線程組,這個線程組在線程創建時指定并在線程的整個生命期內都不能更改。你可以通過調用包含 ThreadGroup 類型參數的 Thread 類構造函數來指定線程屬的線程組,若沒有指定則線程缺省的隸屬于名為system的系統線程組。
在Java中除了預建的系統線程組外,所有線程組都必須顯式創建并且每個線程組又隸屬于另一個線程組。你可以在創建線程組時指定其所隸屬的線程組,若沒有指定則缺省的隸屬于系統線程組。這樣所有線程組組成了一棵以系統線程組為根的樹。
Java線程組實例代碼,具體如下:
源碼參考:http://blog.yoodb.com/yoodb/article/detail/1330
Java允許我們對一個線程組中的所有線程同時進行操作,比如我們可以通過調用線程組的相應方法來設置其中所有線程的優先級,也可以啟動或阻塞其中的所有線程。
Java的線程組機制的另一個重要作用是線程安全。線程組機制允許我們通過分組來區分有不同安全特性的線程,對不同組的線程進行不同的處理,還可以通過線程組的分層結構來支持不對等安全措施的采用。Java 的 ThreadGroup 類提供了大量的方法來方便我們對線程組樹中的每一個線程組以及線程組中的每一個線程進行操作。
以上就是怎么進行Java多線程概念和使用原理的分析,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。