前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java NIO线程的中断机制

Java NIO线程的中断机制

作者头像
Monica2333
发布2020-06-19 17:51:04
9490
发布2020-06-19 17:51:04
举报
文章被收录于专栏:码农知识点码农知识点

Java NIO中InterruptibleChannel接口表示通道IO阻塞时可被异步的关闭和中断。

代码语言:javascript
复制
public interface InterruptibleChannel extends Channel{

    /**
     * Closes this channel.
     *
     *  Any thread currently blocked in an I/O operation upon this channel
     * will receive an AsynchronousCloseException.
     * throws  IOException  If an I/O error occurs
     */
    public void close() throws IOException;
}

AbstractInterruptibleChannel实现了InterruptibleChannel接口,并提供了实现可中断IO机制的重要的方法,比如begin(),end()。在调用IO操作时,需要如此调用才可实现中断:

代码语言:javascript
复制
try {
     begin();
     completed = ...;    // Perform blocking I/O operation
     return ...;         // Return result
  } finally {
     end(completed);
  }

completed参数说明I/O操作是不是真的完成。比如在read操作中,只有completed返回true,才真的表示读到了buffer中一些数据。 在具体的可中断channel中,如FileChannel,SocketChannel,DatagramChannel必须实现implCloseChannel方法,因为这是表示当前channel中断时希望做哪些操作的回调函数。

begin方法: 在io操作的开始之前负责添加Channel的中断处理器到当前线程

代码语言:javascript
复制
 // -- Interruption machinery,持有中断对象 --
    private Interruptible interruptor;
//持有实现中断机制的线程对象
    private volatile Thread interrupted;
    protected final void begin() {
//实例化中断处理对象,
//标记被中断的线程,并回调implCloseChannel,关闭channel
        if (interruptor == null) {
            interruptor = new Interruptible() {
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                        //如果当前channel已被关闭,则直接返回
                            if (!open)
                                return;
                          //设置标志位,登记被中断的线程
                            open = false;
                            interrupted = target;
                            try {
                              //调用具体的实现关闭当前channel
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
      //登记当前线程(当前channel)的中断处理对象
        blockedOn(interruptor);
        Thread me = Thread.currentThread();
      //判断当前线程是不是已经被中断,如果被中断,则手动触发中断操作,关闭channel
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }

可见,nio的channel中断操作,是通过挂载 Interruptible自定义的中断处理对象,当当前线程被中断时,通过回调关闭channel的函数:implCloseChannel,从而实现对当前线程中断的响应。 当前线程如何绑定中断机制对象?看下blockedOn的实现:

代码语言:javascript
复制
// -- sun.misc.SharedSecrets --
    static void blockedOn(Interruptible intr) {         // package-private
        sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
    }

通过JavaLangAccess类将当前线程的blocker设置为interruptor。

当Thread在中断时,如何调用nio的中断处理器?

代码语言:javascript
复制
public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
              //nio中断处理逻辑
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this); //调用中断处理器的中断方法
                return;
            }
        }
    //普通流程,仅设置中断处理标志
        interrupt0();
    }

end 方法:

代码语言:javascript
复制
 protected final void end(boolean completed)
        throws AsynchronousCloseException {
      //释放当前线程的处理器引用,避免线程一直存活无法回收掉中断处理器
        blockedOn(null);
        Thread interrupted = this.interrupted;
        if (interrupted != null && interrupted == Thread.currentThread()) {
        //如果当前线程被中断,则抛出ClosedByInterruptException异常,表示Channel因为线程中断而被关闭了,IO操作也随之中断了。
            interrupted = null;
            throw new ClosedByInterruptException();
        }
        if (!completed && !open){
        //当前线程发现Channel被关闭了,并且是读取还未执行完毕的情况,则抛出AsynchronousCloseException异常,表示Channel被异步关闭了。
            throw new AsynchronousCloseException();
    }

如果手动实现一个可中断的channel时,手动处理中断应该是:

代码语言:javascript
复制
this.outstream = Channels.newChannel(outstream);
try {
    outstream.write(message);
}
catch(AsynchronousCloseException e) {
    System.out.println("Another thread closed the stream while this one was blocking on I/O!");
}
catch(ClosedByInterruptException e) {
    System.out.println("This thread has been interrupted while blocking on I/O!");
}

参考资料: http://www.importnew.com/29430.html https://stackoverflow.com/questions/10087914/how-do-i-use-interruptiblechannel

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档