java.lang.Thread.State:WAITING(parking) LockSupport的park和unpark的基本使用,以及对线程中断的响应性

LockSupport的park和unpark的基本使用,以及对线程中断的响应性

https://blog.csdn.net/aitangyong/article/details/38373137


转载:https://www.cnblogs.com/xuwangs/p/8251728.html

闲话少说,

Tomcat日志报错及堆栈信息:

 

因为这个问题,挂了几个节点。

跟踪报错的代码发现代码中用到future.get()方法:

扫描二维码关注公众号,回复: 1879983 查看本文章
复制代码
        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


猜你喜欢

转载自blog.csdn.net/albertfly/article/details/80828515