Java多線程總結(一)多線程基礎

來源:互聯網
上載者:User

標籤:

本文轉載地址:

            http://www.cnblogs.com/zrtqsk/p/3776328.html

 

  多線程是Java學習的非常重要的方面,是每個Java程式員必須掌握的基本技能。本文只是多線程細節、本質的總結,並無代碼例子入門,不適合初學者理解。初學者學習多線程,建議一邊看書、看博文,以便寫代碼嘗試。

一、進程

  進程是作業系統結構的基礎;是一次程式的執行;是一個程式及其資料在處理機上順序執行時所發生的活動。作業系統中,幾乎所有運行中的任務對應一條進程(Process)。一個程式進入記憶體運行,即變成一個進程。進程是處於運行過程中的程式,並且具有一定獨立功能。描述進程的有一句話非常經典——進程是系統進行資源分派和調度的一個獨立單位。

  進程是系統中獨立存在的實體,擁有自己獨立的資源,擁有自己私人的地址空間進程的實質,就是程式在多道程式系統中的一次執行過程,它是動態產生,動態消亡的,具有自己的生命週期和各種不同的狀態。進程具有並發性,它可以同其他進程一起並發執行,按各自獨立的、不可預知的速度向前推進。 

(注意,並發性(concurrency)和並行性(parallel)是不同的。並行指的是同一時刻,多個指令在多台處理器上同時運行。並髮指的是同一時刻只能有一條指令執行,但多個進程指令被被快速輪換執行,看起來就好像多個指令同時執行一樣。)

  進程由程式資料進程式控制制塊三部分組成。

 

 

二、線程

  線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程式執行流的最小單元。一個標準的線程由線程ID,當前指令指標(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和指派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共用進程所擁有的全部資源。一個線程可以建立和撤消另一個線程,同一進程中的多個線程之間可以並發執行。由於線程之間的相互制約,致使線程在運行中呈現出間斷性。每一個程式都至少有一個線程,若程式只有一個線程,那就是程式本身。

  線程是程式中一個單一的順序控制流程程。在單個程式中同時運行多個線程完成不同的工作,稱為多線程。

    在Java Web中要注意,線程是JVM層級的,在不停止的情況下,跟JVM共同消亡,就是說如果一個Web服務啟動了多個Web應用,某個Web應用啟動了某個線 程,如果關閉這個Web應用,線程並不會關閉,因為JVM還在運行,所以別忘了設定Web應用關閉時停止線程。

 

三、線程狀態  

   

 

(圖片出處:http://www.cnblogs.com/skywang12345/p/3479024.html)

 線程共包括以下5種狀態。
1. 建立狀態(New)         : 線程對象被建立後,就進入了建立狀態。此時它和其他Java對象一樣,僅僅由Java虛擬機器分配了記憶體,並初始化其成員變數值。

2. 就緒狀態(Runnable): 也被稱為“可執行狀態”。線程對象被調用了該對象的start()方法,該線程處於就緒狀態。Java虛擬機器會為其建立方法調用棧和程式計數器。處於就緒狀態的線程,隨時可能被CPU調度執行,取決於JVM中線程調度器的調度。

3. 運行狀態(Running) : 線程擷取CPU許可權進行執行。需要注意的是,線程只能從就緒狀態進入到運行狀態。

4. 阻塞狀態(Blocked)  : 阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:
    (01) 等待阻塞 -- 通過調用線程的wait()方法,讓線程等待某工作的完成。
    (02) 同步阻塞 -- 線程在擷取synchronized同步鎖失敗(因為鎖被其它線程所佔用),它會進入同步阻塞狀態。
    (03) 其他阻塞 -- 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態逾時、join()等待線程終止或者逾時、或者I/O處理完畢時,線程重新轉入就緒狀態。

5. 死亡狀態(Dead)    : 線程執行完了、因異常退出了run()方法或者直接調用該線程的stop()方法(容易導致死結,現在已經不推薦使用),該線程結束生命週期。

 

 

四、wait()、notify()、nofityAll()方法 

  在Object.java中,定義了wait(), notify()和notifyAll()等方法。

  wait()的作用是讓當前線程進入等待狀態,同時,wait()也會讓當前線程釋放它所持有的鎖

  而 notify()和notifyAll()的作用,則是喚醒當前對象上的等待線程;notify()是喚醒單個線程,而notifyAll()是喚醒所有的線程。

Object類中關於等待/喚醒的API詳細資料如下:
  notify()        -- 喚醒在此對象監視器上等待的單個線程,使其進入“就緒狀態”。  
  notifyAll()   -- 喚醒在此對象監視器上等待的所有線程,使其進入“就緒狀態”。
  wait()                                     -- 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法”,當前線程被喚醒(進入“就緒狀態”)。
  wait(long timeout)                 -- 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量”,當前線程被喚醒(進入“就緒狀態”)。
  wait(long timeout, int nanos) -- 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量”,當前線程被喚醒(進入“就緒狀態”)。

 wait()的作用是讓“當前線程”等待(會釋放鎖),而“當前線程”是指正在cpu上啟動並執行線程!

 此處,http://www.cnblogs.com/skywang12345/p/3479224.html例子講的非常詳細。

 

 

五、yield()、sleep()、join()和interrupt()方法  

1、yield() 

  yield()是Thread類的靜態方法。它能讓當前線程暫停,但不會阻塞該線程,而是由“運行狀態”進入到“就緒狀態”,從而讓 其它具有相同優先順序的等待線程擷取執行權;但是,並不能保證在當前線程調用yield()之後,其它具有相同優先順序的線程就一定能獲得執行權;也有可能是 當前線程又進入到“運行狀態”繼續運行!

  值得注意的是,yield()方法不會釋放鎖

 

2、sleep()

  sleep()是Thread類的靜態方法。該方法聲明拋出了InterrupedException異常。所以使用時,要麼捕捉,要麼聲明拋出。

  有2種重載方式:

——static void sleep(long millis)  :  讓當前正在執行的線程暫停millis毫秒,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準度的影響。

——static void sleep(long millis , int nanos)  :  讓當前正在執行的線程暫停millis毫秒加nanos微秒,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準度的影響。

  sleep() 的作用是讓當前線程休眠,即當前線程會從“運行狀態”進入到“休眠(阻塞)狀態”。sleep()會指定休眠時間,線程休眠的時間會大於/等於該休眠時間;線上程重新被喚醒時,它會由“阻塞狀態”變成“就緒狀態”,從而等待cpu的調度執行。常用來暫停程式的運行。  

  同時注意,sleep()方法不會釋放鎖

 

3、join()

  join() 是Thread的一個執行個體方法。表示,當某個程式執行流中調用其他線程的join方法時,調用線程將被阻塞,直到被join的線程執行完畢。

有3種重載的形式:

——join()  :  等待被join的線程執行完成

——join(long millis)  :  等待被join的線程的時間最長為millis毫秒,若在millis毫秒內,被join的線程還未執行結束,則不等待。

——join(long millis , int nanos)  :  等待被join的線程的時間最長為millis毫秒加nanos微秒,若在此時間內,被join的線程還未執行結束,則不等待。

即當前線程內,用某個線程對象調用join()後,會使當前線程等待,直到該線程對象的線程運行完畢,原線程才會繼續運行。

 

4、interrupt()   

  我們經常通過判斷線程的中斷標記來控制線程。   

  interrupt()是Thread類的一個執行個體方法,用於中斷本線程。這個方法被調用時,會立即將線程的中斷標誌設定為“true”。所以當中斷處於“阻塞狀態”的線程時,由於處於阻塞狀態,中斷標記會被設定為“false”,拋出一個 InterruptedException。所以我們線上程的迴圈外捕獲這個異常,就可以退出線程了。

  interrupt()並不會中斷處於“運行狀態”的線程,它會把線程的“中斷標記”設定為true,所以我們可以不斷通過isInterrupted()來檢測中斷標記,從而在調用了interrupt()後終止線程,這也是通常我們對interrupt()的用法。

  Interrupted()是Thread類的一個靜態方法,它返回一個布爾類型指明當前線程是否已經被中斷,isInterrupted()是Thread類的執行個體方法,返回一個布爾類型來判斷線程是否已經被中斷。它們都能夠用於檢測對象的“中斷標記”。區別是,interrupted()除了返回中斷標記之外,它還會清除中斷標記(即將中斷標記設為false);而isInterrupted()僅僅返回中斷標記。

 

 

六、 Synchronized關鍵字

1、原理

  在java中,每一個對象有且僅有一個同步鎖。這也意味著,同步鎖是依賴於對象而存在。

  噹噹前線程調用某對象的synchronized方法時,就擷取了該對象的同步鎖。例如,synchronized(obj),當前線程就擷取了“obj這個對象”的同步鎖。

  不同線程對同步鎖的訪問是互斥的。也就是說,某時間點,對象的同步鎖只能被一個線程擷取到!通過同步鎖,我們就能在多線程中,實現對“對象/方法”的互斥訪問。 例如,現在有個線程A和線程B,它們都會訪問“對象obj的同步鎖”。假設,在某一時刻,線程A擷取到“obj的同步鎖”並在執行一些操作;而此時,線程B也企圖擷取“obj的同步鎖” —— 線程B會擷取失敗,它必須等待,直到線程A釋放了“該對象的同步鎖”之後線程B才能擷取到“obj的同步鎖”從而才可以運行。

 

2、基本規則

  第一條 :  當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程對“該對象”的該“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞。
  第二條 :  當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程仍然可以訪問“該對象”的非同步代碼塊
  第三條 :  當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程對“該對象”的其他的“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞。

 

3、執行個體鎖和全域鎖

執行個體鎖 -- 鎖在某一個執行個體對象上。如果該類是單例,那麼該鎖也具有全域鎖的概念。
               執行個體鎖對應的就是synchronized關鍵字。
全域鎖 -- 該鎖針對的是類,無論執行個體多少個對象,那麼線程都共用該鎖。
               全域鎖對應的就是static synchronized(或者是鎖在該類的class或者classloader對象上)。

  就是說,一個非靜態方法上的synchronized關鍵字,代表該方法依賴其所屬對象。一個靜態方法上synchronized關鍵字,代表該方法依賴這個類本身。

 

 

七、線程優先順序和守護線程 

1、線程優先順序  

  java中的線程優先順序的範圍是1~10,預設的優先順序是5。每個線程預設的優先順序都與建立它的父線程具有相同的優先順序。預設情況下,mian線程具有普通優先順序。“高優先順序線程”會優先於“低優先順序線程”執行。Thread提供了setPriority(int newPriority)和getPriority()方法來設定和返回線程優先順序。

  Thread類有3個靜態常量:

——MAX_PRIORITY = 10

——MIN_PRIORITY = 1

——NORM_PRIORITY = 5

 

2、守護線程

  java 中有兩種線程:使用者線程守護線程。可以通過isDaemon()方法來區別它們:如果返回false,則說明該線程是“使用者線程”;否則就是“守護線程”。
使用者線程一般使用者執行使用者級任務,而守護線程也就是“後台線程”,一般用來執行背景工作。需要注意的是:Java虛擬機器在“使用者線程”都結束後會後退出。

   守護線程又稱“後台線程”、“精靈線程”,它有一個特徵——如果所有前台線程都死亡,後台線程自動死亡

  通過setDaemon(true)來設定一個線程。

 

 

 

 關於Java各種知識的總結,推薦大家一位博主skywang12345, 他的各種Java知識總結實在是詳細易懂且經典,給了我不少協助。

 參考:http://www.cnblogs.com/skywang12345/p/java_threads_category.html

  《瘋狂Java講義》

 

 

Java多線程總結(一)多線程基礎

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.