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