java 中断应用_java中断

理解java中断

Java中断机制是一种协作机制,即通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

中断相关的方法:

public class Thread{

public void interrupt(){} //中断目标线程,实际上就是设置中断状态为true

public boolean isInterrupted(){} //返回目标线程的中断状态

public static boolean interrupted(){} //清除当前线程的中断状态,并返回它之前的值

}

非静态方法和静态方法的区别:

//调用native方法,判断线程是否被中断,不清除中断状态

public boolean isInterrupted() {

return isInterrupted(false);

}

//调用native方法,判断线程是否被中断,清除中断状态

public static boolean interrupted() {

return currentThread().isInterrupted(true);

}

//native方法,测试线程是否被中断。ClearInterrupted决定是否需要清除中断状态

private native boolean isInterrupted(boolean ClearInterrupted);

JVM内部确实为每个线程维护了一个中断标记。但应用程序不能直接访问这个中断变量,必须通过上面几个方法进行操作。通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。

哪些场景可以用到中断?

如果一个方法声明抛出InterruptedException,表示该方法是可中断的。比如sleep、wait、join等。

//Thread类,native方法,当前线程休眠mills毫秒。如果其他线程中断当前线程,则当前线程抛出异常InterruptedException的时候清除当前线程的中断状态。

public static native void sleep(long millis) throws InterruptedException;

//Object类

public final native void wait(long timeout) throws InterruptedException;

public final native void notify();

public final native void notifyAll();

自定义的可中断方法。需要在适合处理中断的地方检测线程中断状态并处理。

if(Thread.currentThread().isInterrupted()){

//do something

}

阻塞方法怎么响应中断

对于自定义的可中断的方法,如上,在必要的时候,判断线程中断状态,来响应中断。当然,如果执行的时候,一直没有判断中断状态,自然也不会响应中断。

java封装的可中断方法,sleep等,是由JVM来控制的。

一些不会抛出 InterruptedException 的线程阻塞操作

然而,对于某些线程阻塞操作,JVM并不会自动抛出InterruptedException异常。例如,某些I/O操作和内部锁操作。对于这类操作,可以用其他方式模拟中断:

java.io中的同步IO

读写socket的时候,InputStream和OutputStream的read和write方法会阻塞等待,但不会响应java中断。不过,调用Socket的close方法后,被阻塞线程会抛出SocketException异常。

利用Selector实现的异步I/O

如果线程被阻塞于Selector.select(在java.nio.channels中),调用wakeup方法会引起ClosedSelectorException异常。

等待获取某个内置锁

如果线程在等待获取一个内部锁,我们将无法中断它。但是,利用Lock类的lockInterruptibly方法,我们可以在等待锁的同时,提供中断能力。

实战

考虑以下场景,使用线程池执行任务,任务包含一系列查询操作和一个修改操作,查询操作可能超时。每个任务的超时时间是3秒。如果FutureTask超时返回,而任务还在继续执行,就会造成数据不一致。这时候需要再查询一次任务的结果才知道执行是否成功。而如果超时之后直接查询,有可能任务还在执行中,这时查到的也是不一样的。此时,可以任务外超时处理中,取消任务;同时,任务内在合适的部分,添加是否中断的判断。如:

//任务外超时处理中,取消任务

try{

SaveResult result = task.get(3000, TimeUnit.MILLISECONDS)); //3s超时

}catch (Exception e){

if(e instanceof TimeoutException){

//超时返回,不知道结果,需要取消任务;参数true表示中断正在执行的操作

task.cancel(true);

}

}

//任务内在合适的部分,添加中断的判断和相关操作

Future task = executor.submit(new Callable() {

@Override

public SaveResult call() throws Exception {

//do something, 1.5s

//do others, 1.5s

//任务内,判断当前线程是否被中断,如果已经被中断,则不执行变更操作

if(!Thread.currentThread.isInterruptrf()){

//update sth

}

return result ;

}

});

看看FutureTask中cancel源码,如果需要中断,则是使用线程中断的方式

public boolean cancel(boolean mayInterruptIfRunning) {

if (state != NEW)

return false;

if (mayInterruptIfRunning) {

if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))

return false;

Thread t = runner;

if (t != null)

t.interrupt();

UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state

}

else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))

return false;

finishCompletion();

return true;

}

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值