java中线程的停止以及LockSupport工具类

看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里,只有两个函数:

  1. public native void unpark(Thread jthread);  
  2. 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 checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

    If this thread is blocked in an invocation of the wait()wait(long), or wait(long, int) methods of the Object class, or of the join()join(long)join(long, int)sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException. (这是正确而且必须的行为,否则就有可能会导致共享变量处于不一致的状态)

    If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread’s interrupt status will be set, and the thread will receive a ClosedByInterruptException.

    If this thread is blocked in a Selector 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 wakeup 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:
    SecurityException – if the current thread cannot modify this thread

所以,对于那些无法响应中断的线程中的逻辑,我们需要根据isInterupted来判断决定是否终止自己,不过不可否认的是,现实中有很多的应用并没有这么做。关于对中断的处理方式,可参考Java theory and practice: Dealing with InterruptedException 。

最后看一下,对于那些使用park阻塞的线程,是否支持Interrupt,看javadoc是支持的,如下:

《java中线程的停止以及LockSupport工具类》

关于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/.

    原文作者:zhjh256
    原文地址: http://www.cnblogs.com/zhjh256/p/6389497.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞