java并发:中断一个正在运行的线程

在某些情况下,我们在线程启动后发现并不需要它继续执⾏下去时,需要中断线程。

要使任务和线程能安全可靠地停止,并不是一件很容易的事情,java没有提供任何机制来安全地终止线程,那么我们该怎么办呢? —— Java提供了线程中断机制来处理需要中断线程的情况。

Java中的线程中断是一种线程间的协作机制,注意事项:在某个线程中对另一个线程调用interrupt()方法并不能直接终止该线程,需要被中断的线程自己处理中断请求

 

下面我们先来了解一下java中的中断机制:

 

interrupt()方法

/**
 * Interrupts this thread.
 *
 * <p> Unless the current thread is interrupting itself, which is
 * always permitted, the {@link #checkAccess() checkAccess} method
 * of this thread is invoked, which may cause a {@link
 * SecurityException} to be thrown.
 *
 * <p> If this thread is blocked in an invocation of the {@link
 * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
 * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
 * class, or of the {@link #join()}, {@link #join(long)}, {@link
 * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
 * methods of this class, then its interrupt status will be cleared and it
 * will receive an {@link InterruptedException}.
 *
 * <p> If this thread is blocked in an I/O operation upon an {@link
 * java.nio.channels.InterruptibleChannel InterruptibleChannel}
 * then the channel will be closed, the thread's interrupt
 * status will be set, and the thread will receive a {@link
 * java.nio.channels.ClosedByInterruptException}.
 *
 * <p> If this thread is blocked in a {@link java.nio.channels.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 {@link
 * java.nio.channels.Selector#wakeup wakeup} method were invoked.
 *
 * <p> If none of the previous conditions hold then this thread's interrupt
 * status will be set. </p>
 *
 * <p> Interrupting a thread that is not alive need not have any effect.
 *
 * @throws  SecurityException
 *          if the current thread cannot modify this thread
 *
 * @revised 6.0
 * @spec JSR-51
 */
public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}

说明:

上述方法并不会⽴即停⽌线程,⽽是设置线程的中断状态为true(默认是flase)

isInterrupted()和interrupted() 的主要区别

非静态方法isInterrupted()用来查询某线程的中断状态,且不会改变该线程的中断状态标识。

源代码的定义如下:

    /**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  {@code true} if this thread has been interrupted;
     *          {@code false} otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    @HotSpotIntrinsicCandidate
    private native boolean isInterrupted(boolean ClearInterrupted);

 

静态方法interrupted()检查中断状态时,中断状态会被清零(置为false)。

调用方式如下:

 

源代码的定义如下:

    /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  {@code true} if the current thread has been interrupted;
     *          {@code false} otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    @HotSpotIntrinsicCandidate
    private native boolean isInterrupted(boolean ClearInterrupted);

 

小结:

从上述源代码的定义可以看到,isInterrupted()和interrupted() 调用了同一个native方法,但是传递的参数不一样。


示例

例一

在下面的例子中,主线程通过调用t.interrupt()方法将线程t的中断状态设置为true,线程t可以在合适的时候调用interrupted()方法或isInterrupted()方法来检测其中断状态并做相应处理:

package com.test;

public class ThreadTest extends Thread {
    public void run() {
        while (true) {
            if (Thread.interrupted()) {
                System.out.println("Someone interrupted me.");
                break;
            } else {
                System.out.println("Going...");
            }
            long now = System.currentTimeMillis();
            while (System.currentTimeMillis() - now < 1000) {
                //让循环持续一段时间,打印的输出语句会少一些
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadTest t = new ThreadTest();
        t.start();
        Thread.sleep(3000);
        t.interrupt();
    }
}

结果如下:

Going...
Going...
Going...
Someone interrupted me.

 结论:

(1)对于非阻塞中的线程, 只是改变了中断状态, 即Thread.isInterrupted()将返回true;

(2)对于可取消的阻塞状态中的线程, 比如等待在Thread.sleep(), Object.wait(), Thread.join(),这些函数上的线程,  这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false.


例二

下面这段程序会使得阻塞在Thread.join()方法上的主线程在收到中断信号后结束:

package com.test;

public class ThreadTest extends Thread { 
    
    private Thread parent;  
    
    public ThreadTest(Thread parent){  
        this.parent = parent;  
    }  
      
    public void run() {  
        while (true) {  
            System.out.println("sub thread is running...");  
            long now = System.currentTimeMillis();  
            while (System.currentTimeMillis() - now < 2000) {  
                //让循环持续一段时间,打印的输出语句会少一些 
            }  
            parent.interrupt();  
        }  
    }  
      
    public static void main(String[] args){  
        ThreadTest t = new ThreadTest(Thread.currentThread());  
        t.start();  
        try {  
            t.join();  
        } catch (InterruptedException e) {  
            System.out.println("Parent thread will die...");  
        }  
    }  
}  

结果如下:

sub thread is running...
Parent thread will die...
sub thread is running...
sub thread is running...
sub thread is running...
sub thread is running...

从结果可以看出,线程t发出中断请求后主线程结束(此时线程t仍在运行)

 

posted @ 2016-03-24 10:58  时空穿越者  阅读(1121)  评论(0)    收藏  举报