开门见山,interrupt()方法的作用,中断一些可以响应中断的阻塞任务(不过好像非阻塞的也可以被中断),如果不能响应中断,则调用该方法将不起作用
阻塞状态:
1.调用sleep(milliseconds)进入睡眠状态
2.调用wait()/await()挂起了线程
3.任务在等待某个输入/输出完成
4.任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁
其中3、4是不可以响应中断的。即调用中断
测试代码:
任务一:SleepBlocked.java
/**
* @author hetiantian
* 可中断的阻塞
*/
public class SleepBlocked implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(100); //当前线程睡眠100秒
} catch (InterruptedException e) {
System.out.println("InterruptedException");
}
System.out.println("Exiting SleepingBlocked.run()");
}
}
任务二: IOBlockeded.java
/**
* @author hetiantian
* 模拟IO阻塞,不可响应中断
*/
public class IOBlockeded implements Runnable {
private InputStream in;
public IOBlockeded(InputStream in) {
this.in = in;
}
@Override
public void run() {
try {
System.out.println("Waiting for read():");
in.read();
} catch (IOException e) {
//如果当前被中断了的话
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted from blocked I/O");
} else {
throw new RuntimeException();
}
}
}
}
任务三:SynchronizedBlocked.java
/**
* @author hetiantian
* 模拟synchronized阻塞的情况
*/
public class SynchronizedBlocked implements Runnable {
//需要获得SynchronizedBlocke上的锁
public synchronized void f() {
while (true) {
Thread.yield(); //让出cpu执行时间
}
}
//构造函数中启动一个线程调用f()方法
public SynchronizedBlocked() {
new Thread() {
public void run() {
f();
}
}.start();
}
@Override
public void run() {
System.out.println("trying to call f()");
//继续调用需要锁的f()方法 //这个线程和构造方法中的线程不是同一个线程,不符合可重入
f();
System.out.println("Exiting SynchronizedBlocked.run()");
}
}
测试类:Interrupting.java
/**
* @author hetiantian
* 测试类
*/
public class Interrupting {
private static ExecutorService es = Executors.newCachedThreadPool();
static void test(Runnable r) throws InterruptedException {
Future<?> f = es.submit(r);
TimeUnit.SECONDS.sleep(100); //调用sleep()方法阻塞当前线程
System.out.println("Interrupting " + r.getClass().getName());
f.cancel(true); //cancel中断由Executor启动的单个线程方法
System.out.println("Interrupt sent to " + r.getClass().getName());
}
public static void main(String[] args) throws InterruptedException {
test(new SleepBlocked());
test(new IOBlockeded(System.in));
test(new SynchronizedBlocked());
TimeUnit.SECONDS.sleep(3); //主线程睡眠3秒让其他线程有机会执行
System.out.println("Aborting with System.exit(0)");
System.exit(0);
}
}
运行结果:
Interrupting SleepBlocked
Interrupt sent to SleepBlocked
InterruptedException
Waiting for read():
Interrupting IOBlocked
Interrupt sent to IOBlocked
trying to call f()
Interrupting SynchronizedBlocked
Interrupt sent to SynchronizedBlocked
Aborting with System.exit(0)
分析运行结果:
1.上述3、4的情况没有响应中断
2.响应了中断以后将执行继续执行后面的代码,执行SleepBlocked任务,在中断以后继续执行了代码,如果不想要执行后面的代码,则通过在catch中加return来实现(我觉得加了return以后才是正真响应了中断,哪有中断了以后还能将后面的代码执行完毕的)
修改以后的代码:
public class SleepBlocked implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(100);
} catch(InterruptedException e) {
System.out.println("InterruptedException");
return;
}
System.out.println("Exiting SleepBlocked.run()");
}
}
对于3、4的情形该怎么让它终端呢
对于3
1)关闭底层资源
2)nio类提供了更人性的I/O中断(不是特别了解nio,只是敲过例子,不展开)
代码如下:
对于4
好像没有办法解决了,难道资源就没办法释放了吗???
对于线程中断还有其他方法:利用标识位,代码如下
任务:Runner.java
/**
* @author hetiantian
* 模拟一个任务
*/
public class Runner implements Runnable {
private long i;
private volatile boolean on = true; //用volatile修饰,保证了可见性
@Override
public void run() {
while (on && !Thread.currentThread().isInterrupted()) {
i++;
}
System.out.println("Count i = " + i);
}
//修改标识位
public void cancel() {
on = false;
}
}
测试类:Shutdown.java
/**
* @author hetiantian
* 一个测试类
*/
public class Shutdown {
public static void main(String[] args) throws InterruptedException {
Runner one = new Runner();
Thread countThread = new Thread(one, "CountThread");
countThread.start();
//执行1秒以后后中断,这里中断采用的是调用interrupt()方法
TimeUnit.SECONDS.sleep(1);
countThread.interrupt();
Runner two = new Runner();
countThread = new Thread(two, "CountThread");
countThread.start();
//睡眠1秒,main线程对Runner two进行取消,on的状态由true--->false
TimeUnit.SECONDS.sleep(1);
two.cancel();
}
}
但用标识位似乎有局限性,它适用于一个线程一直循环调用某个方法的情况次下,我想用标识位解决3、4情况的中断问题,失败了
网友评论