第二章 Java並行程序基礎

第二章 Java並行程序基礎

2.1 有關線程你必須知道的事

  • 線程所有狀態:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

2.2 初始線程:線程的基本操作

2.2.2 終止線程

stop()方法太過暴力,強行把執行一半的線程終止,可能會導致數據不一致。EX:參考36頁

2.2.3 線程中斷

  • 線程中斷並不會使線程立即退出[需要用戶自己處理退出邏輯],中斷只是給線程發送一個通知,有人希望該線程退出。
  • 三個方法:
    • interrupt():實例方法,通知目標線程中斷,設置中斷標誌位
    • isInterrupted():實例方法,判斷當前對象是否被設置了中斷
    • Thread.interrupted():靜態方法,用來判斷當前線程的中斷狀態,但同時會清除當前線程的中斷標誌位狀態
    • 注意:
    • Thread.sleep()方法會拋出中斷異常,如果線程被中斷,進行sleep就會拋出該異常,此時需要捕獲該異常,並在catch中調用Thread.currentThread().interrupt()方法設置中斷狀態,如果不這麼做,則在下一次的循環開始時,就無法捕獲這個中斷。EX:參考40頁

2.2.4 等待(wait)和通知(notify)

wait方法必須包含在synchronized語句中,無論是wait或者notify方法都需要首先獲得目標對象的一個監視器。notify只是在等待隊列中隨機選擇一個進行喚醒,因此是不公平的。EX:參考43頁

2.2.5 掛起(suspend)和繼續執行(resume)線程

被掛起的線程必須等到resume操作後,才能繼續執行。但suspend方法已經被廢棄,因爲該方法不會釋放任何鎖資源,會導致其他任何線程想要訪問被它鎖定的資源時,都會被牽連。而且對於被掛起的線程從它的線程狀態上看,居然還是Runnable。

2.2.6 等待線程結束(join)和謙讓(yield)

  • 一個線程依賴於其他線程,需要等待其他線程執行完才能繼續執行,可以通過join來實現。join的本質是讓線程wait,其實現如下:
    • while(isAlive()) wait(0)
    • 注意:不要在應用程序中,在Thread對象實例上使用類似wait()或者notify()等方法,因爲這很有可能會影響系統API的工作,或者被系統API所影響。
    • yield是一個靜態方法,一旦執行會使當前線程讓出cpu,但其會再次進行cpu資源的競爭,因此可能會讓其再次獲得cpu資源繼續執行。

2.3 volatile與Java內存模型

2.4 分門別類的管理:線程組

ThreadGroup,activeCount方法可以獲取活動的線程總數,由於線程是動態的,因此該值是一個估算值,不是一個精確值。線程組同樣有個stop方法,但同線程的stop方法一樣存在問題。

2.5 駐守後臺:守護線程(Daemon)

與之對應的是用戶線程。當一個Java應用內,只有守護線程時,Java虛擬機就會自然退出。

2.6 先乾重要的事:線程優先級

1到10的級別,但不可以依賴於這些優先級,優先級只是線程獲取cpu資源的機率大些,但並不能確保一定就比低優先級的先獲取到。

2.7 線程安全的概念與synchronized

  • 指定加鎖對象:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。
  • 直接作用於實例方法:相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。
  • 直接作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。

2.8 程序中的幽靈:隱蔽的錯誤

2.8.1 無提示的錯誤案例

如數據類型溢出錯誤

2.8.2 併發下的ArrayList

保存容器大小的變量被多線程不正常訪問、多線程對同一個位置進行了賦值導致異常。

2.8.3 併發下詭異的HashMap

多線程可能會導致put操作中把鏈表破壞,如Key1和Key2互爲對方的next元素,導致成了環形,進入一個死循環,從而導致了程序無法結束。

2.8.4 初學者常見錯誤:錯誤的加鎖

如Integer變量作爲同步synchronized條件,Integer爲不可變對象,即無法修改Integer的值,要修改只能新建一個Integer讓它的值賦值爲新的值;i++實際上調用了i=Integer.valueOf(i.intValue() + 1);該方法爲一個工廠方法。EX:參考67頁

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