java.lang.Thread.State:WAITING(parking) ゝ一纸荒年。 2022-05-21 01:25 101阅读 0赞 # LockSupport的park和unpark的基本使用,以及对线程中断的响应性 # https://blog.csdn.net/aitangyong/article/details/38373137 转载:https://www.cnblogs.com/xuwangs/p/8251728.html 闲话少说, Tomcat日志报错及堆栈信息: ![1235507-20180109145717551-310087763.png][] ![1235507-20180109145545269-588206339.png][] 因为这个问题,挂了几个节点。 跟踪报错的代码发现代码中用到future.get()方法: ![复制代码][copycode.gif] 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); } ![复制代码][copycode.gif] 任务由线程池提供的线程执行,那么这时候主线程则会阻塞,直到任务线程唤醒它们。获取结果时,通过future.get()方法获取: ![1235507-20180109150347801-1138678798.png][] 当 s<= COMPLETING时,表明任务仍然在执行且没有被取消。如果它为true,那么走到awaitDone方法。 下面来看看awaitDone方法里面干了啥: ![复制代码][copycode.gif] /** * 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); } } ![复制代码][copycode.gif] 一屏截图不完整,主要截图引起阻塞的判断条件: ![1235507-20180109151116457-490954864.png][] ![1235507-20180109151127285-131455875.png][] 如果给定的时间是非0(负数)或者给定的时间(正数, 时间单位时毫秒)已经过去了(0的时候会一直阻塞着) 此处因为网络或者其他原因,导致主线程调用future.get()方法时,任务子线程还没有从对接的第三方获取到数据,致使子线程挂起(等待唤醒),从而一直消耗线程池中的资源。 建议修改方案:去掉多线程操作;或者调用future.get(long timeout, TimeUnit unit)方法; 因为当任务正常结束或者异常时,都会调用finishCompletion去唤醒等待线程。 ![1235507-20180109153804457-81732593.png][] 查看官方文档,寻找park方法: ![1235507-20180109151625910-690516096.png][] 字面理解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 [1235507-20180109145717551-310087763.png]: /images/20220521/1456e031341048dab218bd6787472b34.png [1235507-20180109145545269-588206339.png]: /images/20220521/ecdbb4d219d740aead8eab5a2d39457b.png [copycode.gif]: /images/20220521/0c4195089b314b889619d65debc9df3a.png [1235507-20180109150347801-1138678798.png]: /images/20220521/1b6568ee88ec4a34a6f258670bdf0695.png [1235507-20180109151116457-490954864.png]: /images/20220521/0b6b5541c7e94280ac73df94e6f3cd35.png [1235507-20180109151127285-131455875.png]: /images/20220521/d93e3374ec7f482a988215b70afefc58.png [1235507-20180109153804457-81732593.png]: /images/20220521/c1b8e20eeb3a46a79493194f677f7472.png [1235507-20180109151625910-690516096.png]: /images/20220521/b9a955872f9c4d888a26724798db6cde.png
还没有评论,来说两句吧...