爲什麼wait、notify、notifyAll方法定義在Object中而不是Thread類中

多線程概述

Java是一個支持多線程的開發語言,多線程併發執行任務可以充分利用CPU資源,提高多任務併發執行效率(注意區分:多線程並不會加快任務的執行速度,而是可以充分利用多核CPU讓線程輪流進行工作,達到了一種“同時”工作的效果)。

併發時的產生問題

多線程在執行時,會遇到一些問題,問題的關鍵原因則是在共享資源的更新操作上容易產生衝突。

解決的方向

解決衝突的方式則是從共享資源的佔用機制入手,保證共享資源同一時刻只能被一個線程佔用,從而達到數據一致。

具體實現方式中的一種

在Java中提供了synchorinzed關鍵字,在該關鍵字修飾的代碼內,稱爲同步代碼塊,線程執行該區域代碼需要獲取鎖,在獲取成功之後,其他線程需要等該線程執行完畢釋放鎖之後才能獲取到。

wait、notify、notifyAll方法的作用

在同步代碼塊中,可以使用wait、notify來控制當前佔用資源的線程進入阻塞隊列與喚醒進入就緒隊列
也就是說,上述兩個方法實際上實現的時線程之間的通信機制,用來通知線程的阻塞與喚醒。

引出問題:爲什麼定義在Object中而不是Thread類

線程爲了進入臨界區(也就是同步塊內),需要獲得鎖並等待鎖可用,它們並不知道也不需要知道哪些線程持有鎖,它們只需要知道當前資源是否被佔用,是否可以獲得鎖,所以鎖的持有狀態應該由同步監視器來獲取,而不是線程本身。

一個比喻

形象的比喻:一個女孩子同時被10個男孩子追,在同一個時間段內只能陪一個男孩子看電影,當其中一個男孩想要邀請女孩看電影時,應該由女孩子來通知男孩子,這個時間段可不可以赴約,而不應該是男孩子詢問其他情敵抑或是由情敵之間相互通知誰該去赴約(那還不打起來了)。
例子中女孩相當於”共享資源“(每一個男孩機會均等),在Java中是一個對象,男孩子們相當於線程,多個線程之間的通信機制,由共享資源(就是前文所說的同步監視器)來實現,即將wait、notify、notifyAll方法定義在Object中是最合理的

較詳細的解釋

以下是一篇英文博客的翻譯:
爲什麼它們不應該在Thread類,(我)的一些想法是:

  1. wait和nofity不是常見的普通java方法或同步工具,在Java中它們更多的是實現兩個線程之間的通信機制。
    如果不能通過類似synchronized這樣的Java關鍵字來實現這種機制,那麼Object類中就是定義它們最好的地方,以此來使任何Java對象都可以擁有實現線程通信機制的能力。
    記住synchronized和wait,notify是兩個不同的問題域,並且不要混淆它們的相似或相關性。 同步類似競態條件,是提供線程間互斥和確保Java類的線程安全性的,而wait和notify是兩個線程之間的通信機制。

  2. 另一個原因:每個對象都可以作爲鎖

  3. 在Java中,爲了進入臨界區代碼段,線程需要獲得鎖並且它們等待鎖可用,它們不知道哪些線程持有鎖而它們只知道鎖是由某個線程保持,它們應該等待鎖而不是知道哪個線程在同步塊內並要求它們釋放鎖。 這個比喻適合等待和通知在object類而不是Java中的線程。

這些只是我的想法爲什麼wait和notify方法在Object類中聲明,而不是Java中的Thread,當然你可以有不同的觀點。

在現實中,它就是Java不支持操作符重載一樣,只是Java設計者做的一個設計決定。 無論如何,如果你有任何其它令人信服的理由請發佈出來。

還有一點需要注意:wait、notify、notifyAll方法只能在同步代碼塊中使用,在非同步代碼塊中會導致異常

因爲只有在同步代碼塊中才會涉及到鎖的概念,在非併發環境下嘗試操作鎖會導致失敗。

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