top 命令:顯示當前的活動進程,默認它是按消耗 CPU 的厲害程度進行排序
,每5秒鐘刷新一次列表,你也能夠選擇不一樣的排序方式,例如 m 是按內存佔用方式進行排序的快捷鍵。java
命令:top -Hp pid算法
能夠實時的跟蹤並獲取指定進程中最耗cpu的線程
。再用 jstack方法提取到對應的線程堆棧信息
。緩存
jps 命令:安全
jps用來查看JVM裏面全部進程的具體狀態, 包括進程ID,進程啓動的路徑等等。網絡
jstack 命令:數據結構
- 查看java程序崩潰生成core文件,得到core文件的java stack和native stack的信息;
- 查看正在運行的java程序的java stack和native stack的信息:a) 查看運行的java程序呈現hung的狀態;b) 跟蹤Java的調用棧,剖析程序。
線程的狀態分析:多線程
Runnable:該狀態
表示線程具有全部運行條件,在運行隊列中準備操做系統的調度,或者正在運行
。併發Wait on condition:該狀態出如今線程等待某個條件的發生。具體是什麼緣由,能夠結合 stacktrace來分析。
最多見的狀況是線程在等待網絡的讀寫
;另一種出現 Wait on condition的常見狀況是該線程在 sleep,等待 sleep的時間到了時候,將被喚醒
。異步Waiting for monitor entry 和 in Object.wait():在多線程的 JAVA程序中,實現線程之間的同步,就要說說 Monitor。
Monitor是Java中用以實現線程之間的互斥與協做的主要手段,它能夠當作是對象或者 Class的鎖。每個對象都有,也僅有一個 monitor
。jvm
jinfo 命令:
jinfo可觀察運行中的java程序的運行環境參數:
參數包括Java System屬性和JVM命令行參數
;也可從core文件裏面知道崩潰的Java應用程序的配置信息。
jstat 命令:
jstat利用了JVM內建的指令
對Java應用程序的資源和性能進行實時的命令行的監控
,包括了對Heap size和垃圾回收情況的監控等等。
jmap 命令:
觀察運行中的jvm物理內存的佔用狀況
,包括Heap size, Perm size等等。
查看進程ID:top 或者 jps
按CPU使用率展現當前JAVA程序的全部線程:top -Hp 3230
其實這個地方按CPU的使用率來斷定還不太好理解,以運行時間來斷定可能更能說明問題些。
將運行時間最長的 本地線程ID(3244)轉成16進製爲0xcac
。
生成線程堆棧日誌文件 jstack -l 3230 > jstack.log
;
打開堆棧日誌 搜索「0xcac」
:
很容易的就找到了無限循環的調用線程堆棧。
在多線程程序的編寫中,若是不適當的運用同步機制,則有可能形成程序的死鎖,常常表現爲程序的停頓,或者再也不響應用戶的請求。 好比在下面這個示例中,是個較爲典型的死鎖狀況:
在現代的多處理器系統中,提升程序的並行執行能力是 有效利用 CPU 資源的關鍵
。爲了有效協調多線程間的併發訪問,必須採用適當的同步機制來協調競爭
。當前經常使用的多線程同步機制能夠分爲下面三種類型:
volatile 變量:輕量級多線程同步機制,不會引發上下文切換和線程調度。僅提供內存可見性保證,不提供原子性。
CAS 原子指令:輕量級多線程同步機制,不會引發上下文切換和線程調度。它同時提供內存可見性和原子化更新保證。
內部鎖和顯式鎖:重量級多線程同步機制,可能會引發上下文切換和線程調度,它同時提供內存可見性和原子性。
在這裏,CAS 指的是現代 CPU 普遍支持的一種對內存中的共享數據進行操做的一種特殊指令。這個指令會對內存中的共享數據作原子的讀寫操做
。簡單介紹一下這個指令的操做過程:首先,CPU 會將內存中將要被更改的數據與指望的值作比較。而後,當這兩個值相等時,CPU 纔會將內存中的數值替換爲新的值。不然便不作操做。最後,CPU 會將舊的數值返回。這一系列的操做是原子的
。它們雖然看似複雜,但倒是 Java 5 併發機制優於原有鎖機制的根本。簡單來講,CAS 的含義是「我認爲原有的值應該是什麼,若是是,則將原有的值更新爲新值,不然不作修改,並告訴我原來的值是多少」。
在輕度到中度的爭用狀況下,非阻塞算法的性能會超越阻塞算法,由於 CAS 的多數時間都在第一次嘗試時就成功
,而發生爭用時的開銷也不涉及線程掛起和上下文切換,只多了幾個循環迭代。沒有爭用的 CAS 要比沒有爭用的鎖便宜得多(這句話確定是真的,由於沒有爭用的鎖涉及 CAS 加上額外的處理),而爭用的 CAS 比爭用的鎖獲取涉及更短的延遲。
Java的CAS會使用現代處理器上提供的高效機器級別原子指令,這些原子指令以原子方式對內存執行讀-改-寫操做
,這是在多處理器中實現同步的關鍵(從本質上來講,可以支持原子性讀-改-寫指令的計算機器,是順序計算圖靈機的異步等價機器,所以 任何現代的多處理器都會去支持某種能對內存執行原子性讀-改-寫操做的原子指令
)。同時,volatile變量的讀/寫和CAS能夠實現線程之間的通訊
。把這些特性整合在一塊兒,就造成了整個concurrent包得以實現的基石
。若是咱們仔細分析concurrent包的源代碼實現,會發現一個通用化的實現模式:
- 首先,聲明共享變量爲volatile;
- 而後,使用CAS的原子條件更新來實現線程之間的同步;
- 同時,配合以volatile的讀/寫和CAS所具備的volatile讀和寫的內存語義來實現線程之間的通訊。
AQS,非阻塞數據結構和原子變量類(java.util.concurrent.atomic包中的類),這些concurrent包中的基礎類都是使用這種模式來實現的,而concurrent包中的高層類又是依賴於這些基礎類來實現的
。從總體來看,concurrent包的實現示意圖以下:
有鎖、無鎖的本質都是在解決併發狀況下競態資源的線程安全問題。無鎖只是把「排他性」進一步的弱化,以提升併發量,最大限度的使用CPU。
無鎖只會在CPU控制權切換的等待,而有鎖會在「鎖釋放」、「CPU控制權切換」兩種狀況下的等待。
最終無鎖狀況下,CPU使用率上不去,吞吐量降低,就受系統資源限制了
。即便線程量增長,無非增長的是線程CPU控制權的切換成本,統一受CPU的控制調度,出現的也只能是等待了。
volatile關鍵字僅保證兩點:
- volatile變量線程之間可見性;
- 禁止針對volatile變量操做指令重排序;
但最重要一點沒有保證,關係到線程安全,就是Volatile變量操做指令的不保證原子性問題。
什麼是原子操做:
多個線程執行一個操做時,其中任何一個線程要麼徹底執行完此操做的步驟,要麼就沒有執行此操做的任何步驟,那麼認爲這個操做纔是原子的。
關於指令重排序的問題,在單線程中,重排序的先後只要不影響JVM執行結果,JVM能夠運行指令重排序
。
指令重排序的意義在於:
JVM可以根據處理器特性(CPU多級緩存系統、多核處理器等)適當的從新排序機器指令,使機器指令更符合CPU的執行特色,最大限度的發揮機器性能。
可是 在指令重排序在多線程的狀況下,重排序的先後結果,可能不會一致了
。這裏致使結果不一致主要是線程安全的問題,即便指令不重排序,也會存在線程安全問題。這也就是原子性問題、或者沒有加鎖的問題
;