Thread.interrupt()方法可用于中断指定线程,但线程并不是在任何状态下可被立即中断,一般只有当线程处于阻塞状态(调用wait(),join(),sleep()等方法)时才会被立即中断,如果线程处于不可被立即中断状态,那么Thread.interrupt()只会标志线程的中断状态,以便后续操作用于判断,即isInterrupted()方法会返回true.


线程等待获取内部锁的时候,是一种不可立即中断状态,即线程不会立即响应中断而是会继续等待,这种无义无反顾的等待可能会造成资源浪费或者死锁等问题,后果非常严重。新Lock锁提供了等待锁资源时可立即响应中断的lockInterruptibly()方法和tryLock(long time, TimeUnit unit)方法及其实现,当使用这两个方法去请求锁时,如果主通过Thread.interrupt()对它们发起中断,那么它们会立即响应中断,不再继续等待获取锁,这让主线程(管理调度线程)在特殊情况下可以使用生杀大权,以避免系统陷于死锁状态或者避免资源严重浪费。


tryLock(long time, TimeUnit unit)是加强版的tryLock(),又具有lockInterruptibly()的可被中断特性,既可任其超时主动退出又可中断让其被动退出,很多场合可以使用,但如果想让线程只有当被动中断时才退出,那么就使用lockInterruptibly()方法。


通过测试可以得出以下结论:

  • 内部锁(synchronized) 优先响应锁获取再响应中断

  • Lock.lock() 优先响应锁获取再响应中断

  • Lock.tryLock() 判断锁的状态不可用后马上返回不等待

  • tryLock(long time, TimeUnit unit) 优先响应中断再响应锁获取

  • Lock.lockInterruptibly() 优先响应中断再响应锁获取


代码示例:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLockInterrupt {
    private Lock mLock1;
    private Lock mLock2;
    private Lock mLock3;
                                                                                                                                                 
    public TestLockInterrupt(){
        mLock1 = new ReentrantLock();
        mLock2 = new ReentrantLock();
        mLock3 = new ReentrantLock();  
    }
                                                                                                                                                 
    public void f(){
        System.out.println(Thread.currentThread().getName() + ":try to get lock in f().");
                                                                                                                                                     
        try{
            synchronized(this){
                System.out.println(Thread.currentThread().getName() + ":get the lock.");
                                                                                                                                                             
                if(Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName() + ":already marked as interrupted but still running.");
                }
                                                                                                                                                             
                TimeUnit.SECONDS.sleep(100);
            }
                                                                                                                                                         
            System.out.println(Thread.currentThread().getName() + ":release the lock.");
        }
        catch(InterruptedException e){
            System.out.println(Thread.currentThread().getName() + ":interrupted.");
        }          
    }
                                                                                                                                                 
    public void fWithLock(){
        System.out.println(Thread.currentThread().getName() + ":try to get lock in fWithLock().");
                                                                                                                                                     
        mLock1.lock();
        try{
            System.out.println(Thread.currentThread().getName() + ":get the lock.");
                                                                                                                                                         
            if(Thread.currentThread().isInterrupted()){
                System.out.println(Thread.currentThread().getName() + ":already marked as interrupted but still running.");
            }
                                                                                                                                                         
            TimeUnit.SECONDS.sleep(100);
        }
        catch(InterruptedException e){
            System.out.println(Thread.currentThread().getName() + ":interrupted.");
        }
        finally{
            mLock1.unlock();
            System.out.println(Thread.currentThread().getName() + ":release the lock.");
        }          
    }
                                                                                                                                                 
    public void fWithTryLock(){
        System.out.println(Thread.currentThread().getName() + ":try to get lock in fWithTryLock().");
                                                                                                                                                             
        try{
            if(mLock2.tryLock(50, TimeUnit.SECONDS)){
                try{
                    System.out.println(Thread.currentThread().getName() + ":get the lock.");
                                                                                                                                                                 
                    if(Thread.currentThread().isInterrupted()){
                        System.out.println(Thread.currentThread().getName() + ":already marked as interrupted but still running.");
                    }
                                                                                                                                                                 
                    TimeUnit.SECONDS.sleep(100);
                }
                finally{
                    mLock2.unlock();
                    System.out.println(Thread.currentThread().getName() + ":release the lock.");
                }
            }      
        }
        catch(InterruptedException e){
            System.out.println(Thread.currentThread().getName() + ":interrupted.");
        }                  
    }
                                                                                                                                                 
    public void fWithLockInterruptibly(){
        System.out.println(Thread.currentThread().getName() + ":try to get lock in fWithLockInterruptibly().");
                                                                                                                                                     
        try{       
            mLock3.lockInterruptibly();
            System.out.println(Thread.currentThread().getName() + ":get the lock.");
                                                                                                                                                         
            try{
                if(Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName() + ":already marked as interrupted but still running.");
                }
                                                                                                                                                             
                TimeUnit.SECONDS.sleep(100);
            }
            finally{
                mLock3.unlock();
                System.out.println(Thread.currentThread().getName() + ":release the lock.");
            }      
        }
        catch(InterruptedException e){
            System.out.println(Thread.currentThread().getName() + ":interrupted.");
        }          
    }
    private class Worker implements Runnable{
        private int index;
                                                                                                                                                     
        public Worker(int index){
            this.index = index;
        }
                                                                                                                                                     
        @Override
        public void run() {
            switch(index){
            case 1:
                f();
                break;
            case 2:
                fWithLock();
                break;
            case 3:
                fWithTryLock();
                break;
            case 4:
                fWithLockInterruptibly();
                break;
            }
        }  
    }
                                                                                                                                                 
    public static void main(String[] args) {
        TestLockInterrupt testLockInterrupt = new TestLockInterrupt();
                                                                                                                                                     
        for(int i=1; i<=4; i++){
            Thread t1 = new Thread(testLockInterrupt.new Worker(i));
            Thread t2 = new Thread(testLockInterrupt.new Worker(i));
                                                                                                                                                         
            t1.start();
            t2.start();
                                                                                                                                                         
            t1.interrupt();
            t2.interrupt();
        }  
    }
}


代码输出结果:

Thread-0:try to get lock in f().
Thread-1:try to get lock in f().
Thread-1:get the lock.
Thread-3:try to get lock in fWithLock().
Thread-1:already marked as interrupted but still running.
Thread-3:get the lock.
Thread-3:already marked as interrupted but still running.
Thread-7:try to get lock in fWithLockInterruptibly().
Thread-2:try to get lock in fWithLock().
Thread-1:interrupted.
Thread-7:interrupted.
Thread-3:interrupted.
Thread-3:release the lock.
Thread-2:get the lock.
Thread-2:already marked as interrupted but still running.
Thread-2:interrupted.
Thread-2:release the lock.
Thread-4:try to get lock in fWithTryLock().
Thread-4:interrupted.
Thread-0:get the lock.
Thread-0:already marked as interrupted but still running.
Thread-0:interrupted.
Thread-5:try to get lock in fWithTryLock().
Thread-5:interrupted.
Thread-6:try to get lock in fWithLockInterruptibly().
Thread-6:interrupted.