java 线程的几种状态
java thread的運行周期中, 有幾種狀態(tài), 在 java.lang.Thread.State 中有詳細定義和說明:
NEW?狀態(tài)是指線程剛創(chuàng)建, 尚未啟動
RUNNABLE?狀態(tài)是線程正在正常運行中, 當然可能會有某種耗時計算/IO等待的操作/CPU時間片切換等, 這個狀態(tài)下發(fā)生的等待一般是其他系統(tǒng)資源, 而不是鎖, Sleep等
BLOCKED??這個狀態(tài)下, 是在多個線程有同步操作的場景, 比如正在等待另一個線程的synchronized 塊的執(zhí)行釋放, 或者可重入的 synchronized塊里別人調用wait() 方法, 也就是這里是線程在等待進入臨界區(qū)WAITING??這個狀態(tài)下是指線程擁有了某個鎖之后, 調用了他的wait方法, 等待其他線程/鎖擁有者調用 notify / notifyAll 一遍該線程可以繼續(xù)下一步操作, 這里要區(qū)分 BLOCKED 和 WATING 的區(qū)別, 一個是在臨界點外面等待進入, 一個是在臨界點里面wait等待別人notify, 線程調用了join方法 join了另外的線程的時候, 也會進入WAITING狀態(tài), 等待被他join的線程執(zhí)行結束
TIMED_WAITING??這個狀態(tài)就是有限的(時間限制)的WAITING, 一般出現(xiàn)在調用wait(long), join(long)等情況下, 另外一個線程sleep后, 也會進入TIMED_WAITING狀態(tài)
TERMINATED?這個狀態(tài)下表示 該線程的run方法已經執(zhí)行完畢了, 基本上就等于死亡了(當時如果線程被持久持有, 可能不會被回收)
?
下面談談如何讓線程進入以上幾種狀態(tài):
1.?NEW, 這個最簡單了, ? static?void?NEW()?{ Thread?t =?new?Thread?(); System.?out.println(t.getState()); } 輸出NEW 2.?RUNNABLE, 也簡單, 讓一個thread start, 同時代碼里面不要sleep或者wait等 private?static?void?RUNNABLE() { Thread t =?new?Thread(){ public?void?run(){ for(int?i=0; i<Integer.MAX_VALUE; i++){ System.?out.println(i); } } }; t.start(); } 3.?BLOCKED, 這個就必須至少兩個線程以上, 然后互相等待synchronized 塊 private?static?void?BLOCKED() { final?Object lock =?new?Object(); Runnable run =?new?Runnable() { @Override public?void?run() { for(int?i=0; i<Integer.MAX_VALUE; i++){ synchronized?(lock) { System.?out.println(i); } } } }; Thread t1 =?new?Thread(run); t1.setName(?“t1”); Thread t2 =?new?Thread(run); t2.setName(?“t2”); t1.start(); t2.start(); } 這時候, 一個在RUNNABLE, 另一個就會在BLOCKED (等待另一個線程的 System.out.println.. 這是個IO操作, 屬于系統(tǒng)資源, 不會造成WAITING等) 4.?WAITING, 這個需要用到生產者消費者模型, 當生產者生產過慢的時候, 消費者就會等待生產者的下一次notify private?static?void?WAITING() { final?Object lock =?new?Object(); Thread t1 =?new?Thread(){ @Override public?void?run() { int?i = 0; while(true?){ synchronized?(lock) { try?{ lock.wait(); }?catch?(InterruptedException e) { } System.?out.println(i++); } } } }; Thread t2 =?new?Thread(){ @Override public?void?run() { while(true?){ synchronized?(lock) { for(int?i = 0; i< 10000000; i++){ System.?out.println(i); } lock.notifyAll(); } } } }; t1.setName(?“^^t1^^”); t2.setName(?“^^t2^^”); t1.start(); t2.start(); } 5.?TIMED_WAITING, 這個僅需要在4的基礎上, 在wait方法加上一個時間參數(shù)進行限制就OK了. 把4中的synchronized 塊改成如下就可以了. synchronized?(lock) { try?{ lock.wait(60 * 1000L); }?catch?(InterruptedException e) { } System.?out?.println(i++); } 另外看stack的輸出, ?他叫 TIMED_WAITING(on ?object monitor) , 說明括號后面還有其他的情況, 比如sleep, 我們直接把t2的for循環(huán)改成sleep試試: synchronized?(lock) {try?{ sleep(30*1000L); }?catch?(InterruptedException e) { } lock.notifyAll(); } ? 看到了吧, t2的state是 TIMED_WAITING( sleeping), ?而t1依然是on object monitor , 因為t1還是wait在等待t2 notify, 而t2是自己sleep 另外, join操作也是進入 on object monitor 6.?TERMINATED, 這個狀態(tài)只要線程結束了run方法, 就會進入了… private?static?void?TERMINATED() { Thread t1 =?new?Thread(); t1.start(); System.?out.println(t1.getState()); try?{ Thread.?sleep(1000L); }?catch?(InterruptedException?e) { } System.?out.println(t1.getState()); } 輸出:? RUNNABLE TERMINATED 由于線程的start方法是異步啟動的, 所以在其執(zhí)行后立即獲取狀態(tài)有可能才剛進入RUN方法且還未執(zhí)行完畢
?
在找到系統(tǒng)中的潛在性能瓶頸有作用.? 當java系統(tǒng)運行慢的時候, 我們想到的應該先找到性能的瓶頸, 而jstack等工具, 通過jvm當前的stack可以看到當前整個vm所有線程的狀態(tài), 當我們看到一個線程狀態(tài)經常處于 WAITING 或者 BLOCKED的時候, 要小心了, 他可能在等待資源經常沒有得到釋放(當然, 線程池的調度用的也是各種隊列各種鎖, 要區(qū)分一下, 比如下圖) 這是個經典的并發(fā)包里面的線程池, 其調度隊列用的是LinkedBlockingQueue, 執(zhí)行take的時候會block住, 等待下一個任務進入隊列中, 然后進入執(zhí)行, 這種理論上不是系統(tǒng)的性能瓶頸, 找瓶頸一般先找自己的代碼stack,再去排查那些開源的組件/JDK的問題 排查問題的幾個思路: 0. 如何跟蹤一個線程? 看到上面的stack輸出沒有, 第一行是內容是 threadName priority tid nid desc 更過跟蹤tid, nid 都可以唯一找到該線程.? 1. 發(fā)現(xiàn)有線程進入BLOCK, 而且持續(xù)好久, 這說明性能瓶頸存在于synchronized塊中, 因為他一直block住, 進不去, 說明另一個線程一直沒有處理好, 也就這個synchronized塊中處理速度比較慢, 然后再深入查看. 當然也有可能同時block的線程太多, 排隊太久造成.? 2. 發(fā)現(xiàn)有線程進入WAITING, 而且持續(xù)好久, 說明性能瓶頸存在于觸發(fā)notify的那段邏輯. 當然還有就是同時WAITING的線程過多, 老是等不到釋放.? 3. 線程進入TIME_WAITING 狀態(tài)且持續(xù)好久的, 跟2的排查方式一樣.?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的java 线程的几种状态的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 5821 Ball
- 下一篇: RAC实例 表空间 维护