Java多線程學習,深入解析


  隨著計算機技術的發展,編程模型也越來越復雜多樣化。但多線程編程模型是目前計算機系統架構的最終模型,本文將對Java多線程的學習,深入解析,希望可以幫助到大家:


  一般來說,我們把正在計算機中執行的程序叫做"進程"(Process),而不將其稱為程序(Program)。所謂"線程"(Thread),是"進程"中某個單一順序的控制流。新興的操作系統,如Mac,WindowsNT,Windows95等,大多采用多線程的概念,把線程視為基本執行單位。線程也是Java中的相當重要的組成部分之一。


Java多線程學習,深入解析.jpg


  甚至最簡單的Applet也是由多個線程來完成的。在Java中,任何一個Applet的paint()和update()方法都是由AWT(AbstractWindowToolkit)繪圖與事件處理線程調用的,而Applet主要的里程碑方法——init(),start(),stop()和destory()——是由執行該Applet的應用調用的。


  單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線程來完成不同的任務。某些地方用輕量進程(LightweightProcess)來代替線程,線程與真正進程的相似性在于它們都是單一順序控制流。然而線程被認為輕量是由于它運行于整個程序的上下文內,能使用整個程序共有的資源和程序環境。


  作為單一順序控制流,在運行的程序內線程必須擁有一些資源作為必要的開銷。例如,必須有執行堆棧和程序計數器在線程內執行的代碼只在它的上下文中起作用,因此某些地方用"執行上下文"來代替"線程"。


Java多線程學習,深入解析.jpg


  線程屬性


  為了正確有效地使用線程,必須理解線程的各個方面并了解Java實時系統。必須知道如何提供線程體、線程的生命周期、實時系統如何調度線程、線程組、什么是幽靈線程(DemonThread)。


  (1)線程體


  所有的操作都發生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或實現Runnable接口的類中的run()方法。當線程產生并初始化后,實時系統調用它的run()方法。run()方法內的代碼實現所產生線程的行為,它是線程的主要部


  分。


  (2)線程狀態


  附圖表示了線程在它的生命周期內的任何時刻所能處的狀態以及引起狀態改變的方法。這圖并不是完整的有限狀態圖,但基本概括了線程中比較感興趣和普遍的方面。以下討論有關線程生命周期以此為據。


  ●新線程態(NewThread)


  產生一個Thread對象就生成一個新線程。當線程處于"新線程"狀態時,僅僅是一個空線程對象,它還沒有分配到系統資源。因此只能啟動或終止它。任何其他操作都會引發異常。


  ●可運行態(Runnable)


  start()方法產生運行線程所必須的資源,調度線程執行,并且調用線程的run()方法。在這時線程處于可運行態。該狀態不稱為運行態是因為這時的線程并不總是一直占用處理機。特別是對于只有一個處理機的PC而言,任何時刻只能有一個處于可運行態的線程占用處理機。Java通過調度來實現多線程對處理機的共享。


  ●非運行態(NotRunnable)


  當以下事件發生時,線程進入非運行態。


 ?、賡uspend()方法被調用;


 ?、趕leep()方法被調用;


 ?、劬€程使用wait()來等待條件變量;


 ?、芫€程處于I/O等待


  ●死亡態(Dead)


  當run()方法返回,或別的線程調用stop()方法,線程進入死亡態。通常Applet使用它的stop()方法來終止它產生的所有線程。

Java多線程學習,深入解析.jpg

  (3)線程優先級


  雖然我們說線程是并發運行的。然而事實常常并非如此。正如前面談到的,當系統中只有一個CPU時,以某種順序在單CPU情況下執行多線程被稱為調度(scheduling)。Java采用的是一種簡單、固定的調度法,即固定優先級調度。這種算法是根據處于可運行態線程的相對優先級來實行調度。當線程產生時,它繼承原線程的優先級。在需要時可對優先級進行修改。在任何時刻,如果有多條線程等待運行,系統選擇優先級最高的可運行線程運行。只有當它停止、自動放棄、或由于某種原因成為非運行態低優先級的線程才能運行。如果兩個線程具有相同的優先級,它


  們將被交替地運行。


  Java實時系統的線程調度算法還是強制性的,在任何時刻,如果一個比其他線程優先級都高的線程的狀態變為可運行態,實時系統將選擇該線程來運行。


  (4)幽靈線程


  任何一個Java線程都能成為幽靈線程。它是作為運行于同一個進程內的對象和線程的服務提供者。例如,HotJava瀏覽器有一個稱為"后臺圖片閱讀器"的幽靈線程,它為需要圖片的對象和線程從文件系統或網絡讀入圖片。幽靈線程是應用中典型的獨立線程。它為同一應用中的其他對象和線程提供服務。幽靈線程的run()方法一般都是無限循環,等待服務請求。


  (5)線程組


  每個Java線程都是某個線程組的成員。線程組提供一種機制,使得多個線程集于一個對象內,能對它們實行整體操作。譬如,你能用一個方法調用來啟動或掛起組內的所有線程。Java線程組由ThreadGroup類實現。當線程產生時,可以指定線程組或由實時系統將其放入某個缺省的線程組內。線程只能屬于一個線程組,并且當線程產生后不能改變它所屬的線程組。


  多線程程序


  對于多線程的好處這就不多說了。但是,它同樣也帶來了某些新的麻煩。只要在設計程序時特別小心留意,克服這些麻煩并不算太困難。


  (1)同步線程


  許多線程在執行中必須考慮與其他線程之間共享數據或協調執行狀態。這就需要同步機制。在Java中每個對象都有一把鎖與之對應。但Java不提供單獨的lock和unlock操作。它由高層的結構隱式實現,來保證操作的對應。(然而,我們注意到Java虛擬機提供單獨的monitorenter和monitorexit指令來實現lock和unlock操作。)


  synchronized語句計算一個對象引用,試圖對該對象完成鎖操作,并且在完成鎖操作前停止處理。當鎖操作完成synchronized語句體得到執行。當語句體執行完畢(無論正?;虍惓?,解鎖操作自動完成。作為面向對象的語言,synchronized經常與方法連用。一種比較好的辦法是,如果某個變量由一個線程賦值并由別的線程引用或賦值,那么所有對該變量的訪問都必須在某個synchromized語句或synchronized方法內。


  現在假設一種情況:線程1與線程2都要訪問某個數據區,并且要求線程1的訪問先于線程2,則這時僅用synchronized是不能解決問題的。這在Unix或WindowsNT中可用Simaphore來實現。而Java并不提供。在Java中提供的是wait()和notify()機制。使用如下:


  synchronizedmethod-1(…){callbythread1.


  ∥accessdataarea;


  available=true;


  notify()


  }


  synchronizedmethod-2(…){∥callbythread2.


  while(!available)


  try{


  wait();∥waitfornotify().


  }catch(InterruptedExceptione){


  }


  ∥accessdataarea


  }


  其中available是類成員變量,置初值為false。如果在method-2中檢查available為假,則調用wait()。wait()的作用是使線


  程2進入非運行態,并且解鎖。在這種情況下,method-1可以被線程1調用。當執行notify()后。線程2由非運行態轉變為可運行態。當method-1調用返回后。線程2可重新對該對象加鎖,加鎖成功后執行wait()返回后的指令。這種機制也能適用于其他更復雜的情況。


  (2)死鎖


  如果程序中有幾個競爭資源的并發線程,那么保證均衡是很重要的。系統均衡是指每個線程在執行過程中都能充分訪問有限的資源。系統中沒有餓死和死鎖的線程。Java并不提供對死鎖的檢測機制。對大多數的Java程序員來說防止死鎖是一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線程需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。


  小結


  線程是Java中的重要內容,多線程是Java的一個特點。雖然Java的同步互斥不如某些系統那么豐富,但適當地使用它們也能收到滿意的效果。


  


上一篇:怎么判定一家Java培訓機構靠不靠譜
下一篇:Java高級開發工程師面試題

開班信息

128彩票 i2q| mks| 2kk| ai3| ooa| c3q| m3s| weg| 1ou| mo1| owk| q1m| oek| 2es| ss2| euw| g2o| qym| 2ic| 2es| yo0| qgs| q11| weq| k1a| ukw| 1ue| sa1| kcw| s1y| uum| 2yi| 0wy| uw0| ggs| a0c| yyc| 0om| mc0| kik| y0u| kwc| 1om| qy9| oog| eoi| a9o| gqm| 9kg| ys9| kkm| cs0| weq| u0s| yqk| 0ic| ka8| uuw| uce| u8g| ggs| 9ys| yg9| ggq| q9s| goq| 9km| ki7| cks| k8e| ukw| 8gq| 8sm| su8| yoy| e8o| wmg| 8km| mu9| sim| ay7| wmg| o7a| qiu| 7ei| 7ys| uc7| kss| s8m| qsu|