看jstack输出的时候,可以发现很多状态都是TIMED_WAITING(parking),如下所示:
"http-bio-8080-exec-16" #70 daemon prio=5 os_prio=0 tid=0x00007f6088027800 nid=0x3a1f waiting on condition [0x00007f60fcd03000]
java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000006cb8d7500> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078) at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467) at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:86) at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:32) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)关于LockSupport,查看相关资料,可知LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语。LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,只有两个函数:
- public native void unpark(Thread jthread);
- public native void park(boolean isAbsolute, long time);
isAbsolute参数是指明时间是绝对的,还是相对的。
仅仅两个简单的接口,就为上层提供了强大的同步原语。
先来解析下两个函数是做什么的。
unpark函数为线程提供“许可(permit)”,线程调用park函数则等待“许可”。这个有点像信号量,但是这个“许可”是不能叠加的,“许可”是一次性的。
比如线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态。
注意,unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。
在JDK 5里面,是用wait/notify/notifyAll来同步的,它没有LockSupport那样的容忍性。 至于其提供的额外监视器参数,个人觉得没有绝对的必要性,主要是设计上如何考虑的问题,是丢给上层应用自己处理还是同步工具自己提供额外的类帮助器。
我们知道,线程的shutdown从标准的角度来说,就是给线程发送一个interupt,线程自行决定是否响应,具体是否相应的标准如下:
-
interrupt
public void interrupt()
Interrupts this thread.Unless the current thread is interrupting itself, which is always permitted, the method of this thread is invoked, which may cause a to be thrown.
If this thread is blocked in an invocation of the , , or methods of the class, or of the , , , , or , methods of this class, then its interrupt status will be cleared and it will receive an . (这是正确而且必须的行为,否则就有可能会导致共享变量处于不一致的状态)
If this thread is blocked in an I/O operation upon an then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a .
If this thread is blocked in a then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.
- Throws:
-
- if the current thread cannot modify this thread
-
所以,对于那些无法响应中断的线程中的逻辑,我们需要根据isInterupted来判断决定是否终止自己,不过不可否认的是,现实中有很多的应用并没有这么做。关于对中断的处理方式,可参考 。
最后看一下,对于那些使用park阻塞的线程,是否支持Interrupt,看javadoc是支持的,如下:
关于java中断,讲得比较好的帖子是:
http://agapple.iteye.com/blog/970055
关于LockSupport,可参见:
http://blog.csdn.net/hengyunabc/article/details/28126139
以及java doc参考https://docs.oracle.com/javase/7/docs/api/.