對JAVA多線程 並發編程的理解,java多線程並發編程

來源:互聯網
上載者:User

對JAVA多線程 並發編程的理解,java多線程並發編程

對JAVA多線程並發編程的理解

Java多線程編程關注的焦點主要是對單一資源的並發訪問,本文從Java如何?支援並發訪問的角度,淺析對並發編程的理解,也算是對前段時間所學的一個總結。

線程狀態轉換

Java語言定義了5中線程狀態,在任何一個時間點,一個線程只能有且只有其中一種狀態,這5中狀態分別是:

Ø 建立(New):建立後尚未啟動的線程處於這種狀態

Ø 運行(Runable):Runable包括了作業系統線程狀態中的Running和Ready,也就是處於此狀態的線程可能正在執行,也有可能正在等待CPU為它分配執行時間

Ø 無限期等待(Waiting):處於這種狀態的線程不會被分配CPU執行時間,他們要等待被其他線程顯式的喚醒。以下方法會讓線程陷入無限期的等待狀態:

u 沒有設定Timeout參數的Object.wait()方法。

u 沒有設定Timeout參數的Thread.join()方法。

u LockSupport.park()方法。

Ø 限期等待(TimedWaiting):處於這種狀態的線程也不會被分配CPU執行時間,不過無須等待被其他線程顯式地喚醒。在一定時間這後它們會由系統自動喚醒。以下方法會讓線程進行限期等待狀態:

Thread.sleep()方法。

u 設定了Timeout參數的Object.wait()方法。

u 設定了Timeout參數的Thread.join()方法。

u LockSupport.parkNanos()方法

u LockSupport.parkUntil()方法

Ø 阻塞(Blocked):線程被阻塞了,“阻塞狀態”與“等待狀態”的區別是:“阻塞狀態“在等待著擷取到一個排它鎖,這個事件將在另外一個線程放棄這個鎖的時候發生:而”等待狀態“則是在等待一段時間,或都喚醒動作的發生。在程式等待進入同步地區的時候,線程將進入這種狀態。

Ø 結束(Terminated):已終止線程的線程狀態,線程已經結束執行。

各種狀態轉換如:


資源監視器

在進行多線程並行作業時,關鍵的任務是如何保證在並發的多個線程中對競爭資源的安全訪問。所謂安全訪問是指一個線程正在在競爭性資源操作(會修改資源的狀態)時,其它線程不能對該競爭性資源進行操作(如果所有線程都是對該資源進行讀操作,則不會產生安全性問題)。

Java為解決此類問題,提出了監視器的概念。形象的講,一個資源的監視器,好比是在要訪問的資源上包了一層安全防護殼,如:


Java虛擬機器保證,在同一時間點上,有且只會有一個線程獲得該資源的監視器。換句話說,也是獲得了該資源的鎖。獲得鎖的線程可以進行後續操作,沒有獲得鎖的線程則只能進行等待或阻塞。

一個已經獲得該資源的監視器的線程,後續還可以多次獲得該監視器,每獲得一次,鎖計數會加1,每退出一次資源監視器,鎖計數也相應的減1。等到線程完全退出了該資源監視器,鎖計數也清零了。此時,其他線程就可以獲得該資源的監視器了。

Java監視器支援兩種線程,互斥和協作。Java虛擬機器通過對象鎖來實現互斥,允許多個線程在一個共用資料上獨立而互不干擾地工作。協作是通過Object類的wait方法和notify方法來實現,允許多個線程為了同一個目標而共同工作。

互斥可以在多線程中互斥地執行一段被稱作監視地區的代碼,在任務時候,特定監視器上只有一個線程執行監視地區。通常,互斥只在多個線程需要共用資料或其他資源時顯得重要,如果兩個線程並不使用任務公有資料或資源,它們通常會互不干擾,也就不需要進行互斥執行。

互斥協助線程在訪問共用資料時不被其他線程幹擾,而協作協助線程與其他線程共同工作。

當一個線程需要一些特別狀態的資料,而由另一個線程負責改變這些資料的狀態時,協作就顯得非常重要。生產者和消費者就是這樣一個例子。一個”讀線程“會從資料緩衝區中讀取資料,而另一個”寫線程”會向資料緩衝區中寫入資料。讀線程緩衝區處理”非空“狀態時才能讀資料。如果讀線程探索資料緩衝區是空的,它就必須等待。

Java提供”等待並喚醒“的方式來支援多線程的協作行為。對應到Java API上就是Object對象的wait()/notify()/notifyAll()方法。

wait()方法使得當前線程必須要等待,等到另外一個線程調用notify()或者notifyAll()方法。

  當前的線程必須擁有當前對象的monitor,也即lock,就是鎖。

  線程調用wait()方法,釋放它對鎖的擁有權,然後等待另外的線程來通知它(通知的方式是notify()或者notifyAll()方法),這樣它才能重新獲得鎖的擁有權和恢複執行。

  要確保調用wait()方法的時候擁有鎖,即,wait()方法的調用必須放在synchronized方法或synchronized塊中。

  一個小比較:

  當線程調用了wait()方法時,它會釋放掉對象的鎖。

另一個會導致線程暫停方法:Thread.sleep(),它會導致線程睡眠指定的毫秒數,但線程在睡眠的過程中是不會釋放掉對象的鎖的。

notify()方法會喚醒一個等待當前對象的鎖的線程。

  如果多個線程在等待,它們中的一個將會選擇被喚醒。這種選擇是隨意的,和具體實現有關。(線程等待一個對象的鎖是由於調用了wait方法中的一個)。

  被喚醒的線程是不能被執行的,需要等到當前線程放棄這個對象的鎖。

  被喚醒的線程將和其他線程以通常的方式進行競爭,來獲得對象的鎖。也就是說,被喚醒的線程並沒有什麼優先權,也沒有什麼劣勢,對象的下一個線程還是需要通過一般性的競爭。

  notify()方法應該是被擁有對象的鎖的線程所調用。

  (Thismethod should only be called by a thread that is the owner of this object'smonitor.)

  換句話說,和wait()方法一樣,notify方法調用必須放在synchronized方法或synchronized塊中。

前面說wait、nofity、notifyAll方法被調用時,應確保在調用的對象上已經獲得了該對你的監視器。即該線程操作該對象的鎖。

一個線程變為一個對象的鎖的擁有者是通過下列三種方法:

  1.執行這個對象的synchronized執行個體方法。

  2.執行這個對象的synchronized語句塊。這個語句塊鎖的是這個對象。

  3.對於Class類的對象,執行那個類的synchronized、static方法。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.