本文共 5880 字,大约阅读时间需要 19 分钟。
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() 优先响应中断再响应锁获取
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | 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(); } } } |
代码输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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. |