線程安全
- 不可變的對象一定是線程安全的,如:
- final修飾的不可變類:String,Integer
- enum 枚舉類
// 編譯
javac xxx.java
//反編譯
jad xxx.class
同步
- 阻塞式調用,調用方必須等待響應方執行完畢纔會返回
- 同步使用場景:
1、大多數非異步場景(不用異步,就用同步來調用)
如:百度搜索,客戶端同步調用服務端搜索接口,等待服務端實時結果
2、在編排的流程中,必須等待拿到響應結果才能去做下一步操作,且在實時鏈路中相互之間有串聯或關聯數據的。
如:電商中商品詳情頁的查詢接口的內部實現
異步
- 非阻塞式調用,立即返回,調用方無需等待響應方返回實際結果,響應方會通過狀態、通知或回調來告知調用方
- 異步使用場景:
1、耗時任務,主線程中提交耗時任務到線程池,然後通過Feture來異步獲取任務執行結果,這裏也可以由異步任務發消息等途徑來通知主線程。
2、電商下單鏈路的非核心鏈路調用,爲了下單的性能考慮,將訂單下發的發貨倉庫等非實時流程放在後續操作,提高下單的響應速度。 如:這裏交易系統通過消息自發自接等方式來驅動後續流程
同步異步優劣勢比較
阻塞
- 調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後纔會返回
非阻塞
- 非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程,而會立即返回。
單線程程序
- 程序執行過程中始終只有一個線程在運行,後面的代碼段必須等到前面代碼段的任務執行完畢後才能執行,這樣的程序可以認爲是單線程程序。
多線程程序
- 程序由多個線程構成,方法內各代碼塊執行順序是不確定的,這樣的程序可以認爲是多線程程序。
併發
- 邏輯上的同時處理。能處理多個事件,但是並不一定是同時進行的。
- 這裏可能只有一個處理器的多個線程,由系統的調度,讓不同的線程在不同的小的時間段內執行各自的線程任務邏輯。
並行
- 物理或是實際的同時處理。能在同一時刻處理多個事件。
- 並行具有併發的含義,併發不一定是並行的,因爲不是同時進行。
線程的狀態
- NEW:線程創建但是還沒有調用start()方法
- RUNNABLE :可運行線程的狀態,線程已經在JVM虛擬機中執行,但是可能需要等待操作系統資源,如處理器。RUNNABLE包括RUNNING和READY
- BLOCKED :阻塞的線程意味着正在等待監視器鎖,來進入或重入synchronized代碼塊或者方法
- WAITING :等待狀態,需要其他線程中斷或通知來喚醒
- TIMED_WAITING:定時等待狀態,在指定等待時間後返回,或提前被其他線程中斷或通知返回
- TERMINATED:終止線程的線程狀態,線程已執行完成
線程的狀態切換
線程方法
Thread.yield()
- 線程讓步,使用了這個方法,當前線程就會退出CPU時間片,讓其他線程或當前線程使用CPU時間篇執行
Thread.sleep()
- 線程休眠,主動讓出當前CPU時間,在指定時間過後,CPU會返回繼續執行該線程。sleep方法不會釋放當前所持有的鎖
Thread.join()
- 等待該線程死亡/終止,當前線程會等待調用該方法的線程執行完畢後才能繼續執行
Object.wait()
- Object類的方法,調用前必須擁有對象鎖,例如在synchronized代碼塊內,調用wait方法後,對象鎖會釋放,線程進入WAITING等待狀態
線程死鎖
- 死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。
- 兩個及以上的線程,搶佔2把及以上的鎖,搶佔鎖的順序不一致
避免和處理死鎖問題
1.不使用鎖,不使用2把及以上的鎖
2.必須使用2把及以上鎖的時候,確保在整個應用程序中對獲取鎖的順序是一致的
3.嘗試獲取具有超時釋放的鎖,例如Lock中的tryLock來獲取鎖
4.當發生了Java-level的鎖時,重啓程序來幹掉進程/線程
定位死鎖問題
-
jps
列舉正在運行的虛擬機進程並顯示虛擬機執行的主類以及這些進程的唯一ID(PID) -
jstack
用於JVM當前時刻的線程快照,得到JVM當前每一條線程正在執行的堆棧信息,定位線程長時間卡頓問題,如死鎖、死循環等問題