线程的Interrupt方法与InterruptedException解析
-
线程阻塞状态与等待状态(当一个线程处于被阻塞或等待状态时,它暂时不活动,不允许任何代码且消耗最少的资源)
-
当一个线程试图获得一个内部的对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态
-
当一个线程等待另一个线程通知调度器的一个条件时,它自己进入等待状态。在调用Object.wait方法或Thread.join方法,或者是等待java.util.concurrent库中的Lock或Condition时,就会出现这种情况。实际上被阻塞状态与等待状态是有很大不同的
-
带有超时参数的方法,调用它们线程会进入计时等待状态。这一状态将一直保持到超时期满或者接收到适合的通知。带有超时的方法有Thread.sleep、Object.wait、Thread.join、Lock.tryLock、Condition.await
-
没有强制线程终止的方法。然而Interrupt方法可以用来请求终止线程,当对一个线程调用interrupt方法时,线程的中断状态被置位,这是每一个线程都有的boolean状态,每个线程应该不是的检查这个标志,以判断线程是否被中断。当一个线程的中断状态被置位时,被中断的线程决定如何响应中断
-
intrrupt方法,用来中断线程
-
interrupted是一个静态方法,它检测当前线程是否被中断。而且,该方法会清除该线程的中断状态,重置中断状态为false
-
isInterrupted是一个实例方法,检验是否有线程被中断,不会改变中断状态
-
线程中断时抛出InterruptedException异常解析
-
当一个线程调在sleep方法时,如果在该线程上调用interrupt方法,将抛出异常
-
当一个线程进入一个同步阻塞( synchronize(o))的等待集wait时,调用interrupt方法,将抛出异常
-
当线程等待concurrent库中锁Lock时,被中断不抛异常
-
当线程进入concurrent库中条件等待集await时,被中断不抛异常
-
如果在中断状态被置位时调用sleep方法,不会休眠,反而会清除这一状态(!)并抛出InterruptException异常
-
锁测试与超时
-
tryLock方法试图申请一个锁,在成功获得锁后返回true,否则,立即返回false。而且线程可以离开去做其他事情
-
lock方法不能被中断。如果一个线程在等待获得一个锁时被中断,并不会抛出异常。中断线程在获得锁之前一直处于阻塞状态。如果出现死锁,那么,lock方法就无法终止
-
然而,如果调用带有超时参数的tryLock(1000,TimeUnit.MILLISECONDS),那么如果线程在等待期间被中断,将会抛出InterruptedException异常。这是一个非常有用的特性,因为允许程序打破死锁
// 当一个线程调在sleep方法时,如果在该线程上调用interrupt方法 public class Demo { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); System.out.println("end"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); Thread.sleep(1000); t.interrupt(); // 抛出异常 } } // 当一个线程进入一个同步阻塞( synchronize(o))的等待集wait时 public class Demo { public Object o = new Object(); public void fun() throws InterruptedException { synchronized (o) { o.wait(); } } public static void main(String[] args) throws InterruptedException { Demo demo = new Demo(); Thread t = new Thread(new Runnable() { @Override public void run() { try { demo.fun(); System.out.println("end"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); Thread.sleep(1000); t.interrupt(); // 抛出异常 } } // 当线程等待concurrent库中锁Lock时 public class Bank { private Lock bankLock; private Condition sufficientFunds; public Bank() { bankLock = new ReentrantLock(); sufficientFunds = bankLock.newCondition(); } public void transfer() throws InterruptedException { bankLock.lock(); // 线程t2不抛出异常,可能发生同步阻塞,建议使用带超时的tryLock(1000,TimeUnit.MILLISECONDS),调用interrupt时抛出异常 // if (bankLock.tryLock()) // 线程t2获取不到锁,立即离开做其他事情 // if (bankLock.tryLock(3000, TimeUnit.MILLISECONDS)) // 线程t2抛出异常 // { try { while (true) { } } finally { bankLock.unlock(); } // } } public static void main(String[] args) throws InterruptedException { Bank bank = new Bank(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { bank.transfer(); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); bank.transfer(); System.out.println("end"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); t2.start(); Thread.sleep(2000); t2.interrupt(); } } // 当线程进入concurrent库中条件等待集await时 public class Bank { private Lock bankLock; private Condition sufficientFunds; public Bank() { bankLock = new ReentrantLock(); sufficientFunds = bankLock.newCondition(); } public void transfer(boolean b,boolean c) throws InterruptedException { bankLock.lock(); try { if (b) sufficientFunds.await(); while (c) { } sufficientFunds.signalAll(); } finally { bankLock.unlock(); } } public static void main(String[] args) throws InterruptedException { Bank bank = new Bank(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { bank.transfer(true,false); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); bank.transfer(false,true); System.out.println("end"); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); t2.start(); Thread.sleep(2000); t1.interrupt(); } }