java.lang.Thread.State:WAITING(parking)


閑話少說,

Tomcat日志報錯及堆棧信息:

 

因為這個問題,掛了幾個節點。

跟蹤報錯的代碼發現代碼中用到future.get()方法:

        Callable<Object> myCallable = createThreadCallable(interfaceName, httpbody, authSeedVo); Future<Object> future = threadPool.submit(myCallable); try { super.sendJson(future.get().toString()); } catch (Exception e) { logger.error("delsub", "獲取子線程時發生異常", e); }

任務由線程池提供的線程執行,那么這時候主線程則會阻塞,直到任務線程喚醒它們。獲取結果時,通過future.get()方法獲取:

當 s<= COMPLETING時,表明任務仍然在執行且沒有被取消。如果它為true,那么走到awaitDone方法。

下面來看看awaitDone方法里面干了啥:

 

  /** * Awaits completion or aborts on interrupt or timeout. * * @param timed true if use timed waits * @param nanos time to wait, if timed * @return state upon completion */
    private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; } else if (s == COMPLETING) // cannot time out yet
 Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } else LockSupport.park(this); } }

一屏截圖不完整,主要截圖引起阻塞的判斷條件:

如果給定的時間是非0(負數)或者給定的時間(正數, 時間單位時毫秒)已經過去了(0的時候會一直阻塞着)

此處因為網絡或者其他原因,導致主線程調用future.get()方法時,任務子線程還沒有從對接的第三方獲取到數據,致使子線程掛起(等待喚醒),從而一直消耗線程池中的資源。

建議修改方案:去掉多線程操作;或者調用future.get(long timeout, TimeUnit unit)方法;

因為當任務正常結束或者異常時,都會調用finishCompletion去喚醒等待線程。

 

 

查看官方文檔,尋找park方法:

字面理解park,就算占住,停車的時候不就把這個車位給占住了么?起這個名字還是很形象的。unpark,占住的反義詞,就是釋放。把車從車位上開走。

翻譯一下:

  • park:阻塞當前線程,(1)當配對的unpark發生或者(2)配對的unpark已經發生或者線程被中斷時恢復(unpark先行,再執行park)。 (3)當absolute是false時,如果給定的時間是非0(負數)或者給定的時間(正數, 時間單位時毫秒)已經過去了(0的時候會一直阻塞着)。(4)當Absolute是true時,如果給定的時間(時間單位是納秒)過去了或者偽造的(在我理解是參數不合法時)線程會恢復中斷。這個操作是不安全的,所以在其他調用會很奇怪(奇怪?反正就是用的時候要小心)
  • unpark:當指定線程被park命令阻塞時unpark命令可以恢復阻塞。在park命令沒有被先調用過的時候,調用unpark,線程仍然不被阻塞。

參考文章:

java.util.concurrent.locks.LockSupport類詳解:https://my.oschina.net/readjava/blog/282882

futureTask:http://www.cnblogs.com/maypattis/p/5827671.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM