对于这些一系列的方法,首先得清楚的知道线程运行状态的转换才能更好的去理解。
一个线程声明周期:初始,就绪,运行,阻塞,运行,死亡。
(图为网上找的,侵删!!!)
有三种原因引起阻塞: 等待阻塞、同步阻塞、其他阻塞(睡眠,join,IO阻塞)
在Java的方法中,等待是wait,同步是syn块,睡眠是sleep,join阻塞是join产生的。
一般我们都会说interrupt是中断标志,那么我们详细来说说:
一个线程不应该由其他线程来强制中断或停止,应该由自己去中断,
故 Thread.stop, Thread.suspend, Thread.resume都已经废弃了。
而Thread.interrupt并不能中断线程,只是通知线程“你应该中断了”。
那么接下来,再来看看差不多的命名方法
查看api可以知道有三个类似的方法。
两个区别:
1. interrupted是静态方法,作用与当前线程, isInterrupted作用于调用该方法的线程对象所对应的线程。
(线程对象对应的线程不一定是当前运行的线程)
2. 这两个方法都是同一个方法,只是参数不一样,看上面注释,就能明白,前者是有清楚标记的作用。
一般的,通过interrupt和interrupted方法两者的配合可以实现正常去停止一个线程,线程A通过线程B的interrupt方法通知线程B让它结束线程,在线程B的run内部中,循环检测interrupted是否真来接受线程A的信号,如果为真就可以抛出一个异常,在catch中完成清理工作,然后结束线程。
如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞状态的情况来进行处理;例如,一个线程在运行状态中,其中断标志被设置为true,则此后,一旦线程调用了wait、jion、sleep方法中的一种,立马抛出一个InterruptedException,且中断标志被清除,重新设置为false。程序员用try-catch来捕捉Jvm抛出的异常来做各种处理,如何时退出线程。
来看几个例子:
public class Test { public static void main(String[] args) { Thread t = new Thread(new worker()); t.start(); try{ Thread.sleep(200); //System.out.println(Thread.currentThread().isInterrupted()); 表示当前main线程 //System.out.println(t.isInterrupted()); work子线程 }catch (InterruptedException e){ System.out.println("main is exception"); } t.interrupt(); System.out.println("Main Thread is stopped"); } } class worker extends Thread{ @Override public void run() { super.run(); //System.out.println(Thread.currentThread().isInterrupted()); // 表示的是当前work线程 System.out.println("work is start"); try{ Thread.sleep(500); }catch (InterruptedException e){ System.out.println("work isInterrupted()" + Thread.currentThread().isInterrupted()); } System.out.println("work is stop"); } }
主线程启动一个子线程,让worker线程睡500ms,而main睡200ms,之后main调用work的interrupt方法中断work(通知work你该自己了结了),work被打断了,要知道main的没有抛出异常,work抛出异常了,且中断标志清除了。
public class Test1 { public static void main(String[] args) { try{ MyThread thread = new MyThread(); thread.start(); Thread.sleep(200); thread.interrupt(); }catch (InterruptedException e){ System.out.println("main catch"); } System.out.println("end"); } } class MyThread extends Thread{ @Override public void run() { super.run(); try { System.out.println("run begin"); Thread.sleep(200000); System.out.println("run end"); }catch (InterruptedException e){ System.out.println("在沉睡中停止" + this.isInterrupted()); e.printStackTrace(); } } }
把主线程中的interrupt和sleep交换一下,清除执行顺序、 稍微注意一下sleep和interrupt的顺序区别。
停止线程的方法——异常法
public class Test { public static void main(String[] args) { try{ MyThread thread = new MyThread(); thread.start(); Thread.sleep(10); // 时间不要定的太长了,否则直接运行完了还没开始标记中断 thread.interrupt(); }catch (InterruptedException e){ System.out.println("main catch"); } System.out.println("end"); } } class MyThread extends Thread{ @Override public void run() { super.run(); try { for(int i = 0; i < 50000; i ++){ if(Thread.interrupted()){ System.out.println("停止了"); throw new InterruptedException(); } System.out.println("i= " + (i + 1)); } System.out.println("测试输出"); // 输出不来是因为直接抛出了异常catch到了 }catch (InterruptedException e){ System.out.println("进入了catch中"); e.printStackTrace(); } } }
总结:
interrupt设置标志位,在非阻塞状态下,将改为true,一旦进入阻塞状态,则会抛出异常,且中断标志清除
interrupted是静态方法,返回的是当前线程的中断状态,第一次调用返回true,然后清除标记,第二次就是false,当然,这期间没有抛出中断异常,否则中断异常就会被清除。
isInterrupted调用的话,一直会返回true,除非中断状态被清除了。