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.