JavaNIO - AbstractInterruptibleChannel

1. 描述

可异步关闭和中断的Channel。

(1)实现InterruptibleChannel接口的Channel支持异步关闭:如果一个线程IO阻塞在一个可中断的channel,另一个线程可以执行channel的close方法。这将导致阻塞线程收到AsynchronousCloseException异常。

(2)实现InterruptibleChannel接口的Channel支持中断:如果一个线程IO阻塞在一个可中断的Channel,另一个线程可以执行阻塞线程的interrupt方法。这将导致Channel关闭,阻塞线程收到ClosedByInterruptException异常,阻塞线程将是interrupted状态。

(3)如果线程已经中断,然后在Channel执行阻塞IO操作,channel将关闭,线程将立刻收到ClosedInterruptException异常,且中断状态会保持。

(4)只有实现InterruptibleChannel的Channel才支持异步关闭和中断。

2. Interruptible,InterruptibleChannel,AbstractInterruptibleChannel 

2.1 API

 

package sun.nio.ch;
public interface Interruptible {

    public void interrupt(Thread t);

}

package java.nio.channels;
public interface InterruptibleChannel
    extends Channel
{

     // 关闭Channel
     // 任何线程在channel上面IO阻塞,都会收到AsynchronousCloseException异常
    public void close() throws IOException;

}

package java.nio.channels.spi;
 // 可中断Channel的基本实现
 // 这个类封装底层机制去实现Channel异步关闭和中断。一个具体Channel必须在可能导致IO阻塞之前执行begin方法,之后执行end方法;其中为了保证end必须执行,必须放在try{}finally{}
 // 如:
 // boolean completed = false;
 // try {
 //        begin();
 //        completed = ...; // 执行IO阻塞操作
 //        return;   
 // } finally {
 //        end(completed);
 // }      
 // completed标示IO操作是否完成,即对调用者是可见的。
public abstract class AbstractInterruptibleChannel
    implements Channel, InterruptibleChannel
{

    private final Object closeLock = new Object(); // 关闭需要加锁
    private volatile boolean open = true; // 是否打开

    protected AbstractInterruptibleChannel() { }

    // 关闭Channel
    // 如果Channel已经关闭,这个方法立刻返回;否则标记channel为关闭状态,然后执行implCloseChannel去执行真实的关闭操作。
    public final void close() throws IOException {
        synchronized (closeLock) {
            if (!open)
                return;
            open = false;
            implCloseChannel();
        }
    }

    // 这个方法被close调用去执行真实的channel关闭工作。该方法只有在channel还没有关闭的情况下被调用,从来不会被调用多次。
    // 此方法的实现必须设定:在调用关闭方法的时候,在此通道上的I/O操作中阻塞的任何其他线程立即返回,要么抛出异常,要么返回正常。
    protected abstract void implCloseChannel() throws IOException;

    public final boolean isOpen() {
        return open;
    }


    // -- Interruption machinery --

    private Interruptible interruptor; 
    private volatile Thread interrupted; // 被中断的线程

    // 标记可能IO阻塞的开始,这个方法必须和end匹配使用。
    protected final void begin() {
        if (interruptor == null) {
            interruptor = new Interruptible() {
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                            if (!open)
                                return;
                            open = false;
                            interrupted = target;
                            try {
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
        blockedOn(interruptor);
        Thread me = Thread.currentThread();
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }

    // 标记可能IO阻塞的结束,这个方法必须和begin匹配使用。
    // completed: IO操作是否完成。
    // 如果Channel被异步关闭,抛出AsynchronousCloseException
    // 如果阻塞线程被中断,抛出ClosedByInterruptException
    protected final void end(boolean completed)
        throws AsynchronousCloseException
    {
        blockedOn(null);
        Thread interrupted = this.interrupted;
        if (interrupted != null && interrupted == Thread.currentThread()) {
            interrupted = null;
            throw new ClosedByInterruptException();
        }
        if (!completed && !open)
            throw new AsynchronousCloseException();
    }


    // 设置当前线程实例的blocker字段值为intr。
    static void blockedOn(Interruptible intr) {         // package-private
        sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(),
                                                             intr);
    }
}

AbstractInterruptibleChannel定义了调用模式: 

boolean completed = false;  
try {  
    begin();  
    completed = ...;    // Perform blocking I/O operation  
    return ...;         // Return result  
} finally {  
    end(completed);  

(1)ClosedByInterruptException

怎么实现线程中断时关闭channel呢?不能指望调用者调用thread.interrupt()后,在调用Channel.close()

能够想到的办法就是将channel的close方法放到thread.interrupt()方法中,JDK即使这么做的,下面会对Thread的interrupt方法做介绍。  

(2)AsynchronousCloseException

当一个线程阻塞在channel上,另一个线程调用channel的close方法,怎么实现阻塞线程抛出异常呢?难点在channle的close方法必须通知阻塞的线程,让它中断。

具体可以看看sun.nio.ch.ServerSocketChannelImpl里面的implCloseSelectableChannel实现。  

2.2 类图

2.3 AbstractInterruptibleChannel源码分析

 首先看看Thread类的interrupt方法实现:

class Thread {
    // 该线程在可中断的I/O操作中被阻塞的对象,如果有的话。
    // blocker的interrupt方法在设置线程中断状态之后必须被执行。 
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();

    void blockedOn(Interruptible b) { // 设置blocker字段
        synchronized (blockerLock) {
            blocker = b;
        }
    }
 public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this); // 回调blocker的interrupt方法
                return;
            }
        }
        interrupt0();
    }
    

}  

2.3.1 begin

下面看看AbstractInterruptibleChannel的begin方法:

protected final void begin() {
        if (interruptor == null) { // 初始化Interruptible对象
            interruptor = new Interruptible() {
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                            if (!open)
                                return;
                            open = false;
                            interrupted = target;
                            try { // 关闭可中断的Channel
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
        // 设置当前线程实例的blocker字段值为interruptor,保证在调用当前线程的interrupt方法时,可以回调前面初始化Interruptible对象的interrupt方法,从而关闭可中断Channel
        blockedOn(interruptor); 
        Thread me = Thread.currentThread();
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }  

补充一点:AbstractInterruptibleChannel的blockedOn(Interruptible intr)方法的实现:

static void blockedOn(Interruptible intr) {         // package-private
        sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(),
                                                             intr);
    }  

JavaLangAccess是接口,里面有方法blockedOn

/** Set thread's blocker field. */
void blockedOn(Thread t, Interruptible b);  

 而在System.setJavaLangAccess()方法中有个JavaLangAccess的匿名内部类实现,其中blockedOn方法的实现如下:

public void blockedOn(Thread t, Interruptible b) {
                t.blockedOn(b); // 调用Thread类的方法设置blocker
            }

2.3.2 end

protected final void end(boolean completed)
        throws AsynchronousCloseException
    {
        blockedOn(null);// 清空线程的blocker字段
        // 如果线程被中断,则在begin里面初始化的Interruptible对象的interrupt方法里面设置了interrupted变量为被中断的线程。
        Thread interrupted = this.interrupted; 
        if (interrupted != null && interrupted == Thread.currentThread()) {
            interrupted = null;
            throw new ClosedByInterruptException(); // 如果被中断,则抛出ClosedByInterruptException异常
        }
        if (!completed && !open) // 如果被close,则抛出AsynchronousCloseException异常
            throw new AsynchronousCloseException();
    }

3. 参考资料

1. JDK1.8.0_111

2. http://jnullpointer.iteye.com/blog/2119982  

转载于:https://www.cnblogs.com/lujiango/p/8478154.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: nio-multipart 是一个用于处理 Multipart 请求的依赖。Multipart 请求是一种 HTTP 请求格式,允许在单个请求中传输多种类型的数据,包括文本、文件、图像等。nio-multipart 提供了处理这种请求格式的工具和功能。 使用 nio-multipart,开发人员可以轻松地解析和处理 Multipart 请求。它提供了一种简单而灵活的方式,可以从请求中提取不同的数据部分,并以可读的格式进行操作。无论是处理上传的文件、解析数据字段还是获取请求的属性,nio-multipart 都提供了便捷的方法。 该依赖还支持文件上传,并提供了一套完整的 API 来处理上传的文件。使用 nio-multipart,开发人员可以轻松地接收上传的文件,并对其进行验证、存储和处理。它还支持上传文件的大小限制、文件类型验证等常见的文件处理需求。 nio-multipart 还提供了处理编码类型的支持。开发人员可以使用 nio-multipart 来处理不同的编码类型,例如表单数据的 URL 编码或二进制数据的 base64 编码。它还提供了编码类型之间的转换,以便开发人员可以方便地在不同的编码类型之间进行转换。 总而言之,nio-multipart 是一个用于处理 Multipart 请求的依赖,它提供了解析、处理和操作 Multipart 请求的功能,包括数据字段的提取、文件上传的支持和编码类型的处理等。使用 nio-multipart,开发人员可以更加便捷地处理复杂的请求格式,提高开发效率。 ### 回答2: NIO-Multipart是一个Java库工具,它提供了一种使用非阻塞I/O(NIO)实现的提供文件上传和处理多部分表单数据的方法。在Web应用程序开发中,常常需要处理用户提交的文件和表单数据,而NIO-Multipart可以帮助开发人员轻松地实现这些功能。 具体来说,NIO-Multipart提供了以下功能和依赖: 1. 文件上传:NIO-Multipart可以将客户端上载的文件保存到服务器的指定位置。它提供了一种简便的方法来访问上传的文件和相关的表单数据。 2. 处理多部分表单数据:NIO-Multipart可以解析提交的多部分表单数据,包括普通的表单字段和文件字段。它可以将这些数据提取出来,并以易于使用的方式提交给开发人员进行处理。 3. 依赖:NIO-Multipart依赖于JavaNIO库,使用其提供的非阻塞I/O(NIO)功能来处理文件上传和表单数据。 使用NIO-Multipart库,开发人员可以轻松处理和管理文件上传和多部分表单数据。通过利用非阻塞I/O(NIO)的优势,可以实现高效的文件传输和数据处理,提升了Web应用程序的性能和用户体验。 总之,NIO-Multipart是一种用于处理文件上传和多部分表单数据的Java库工具,它依赖于JavaNIO库,提供了一种使用非阻塞I/O实现的方法。 ### 回答3: nio-multipart是Java中的一个依赖库,用于处理基于NIO的多部分请求(multipart requests)。 首先,多部分请求是一种HTTP请求类型,允许在单个请求中传输多个文件和文本数据。它通常用于文件上传功能,在Web应用程序中非常常见。 nio-multipart提供了一种简单和高效的方式来解析和处理多部分请求。它基于JavaNIO(New I/O)库开发,该库提供了更快和更强大的I/O操作功能。 使用nio-multipart,我们可以轻松地从多部分请求中提取文件和文本数据,并对它们进行处理。它提供了易于使用的API,用于读取和解析请求的各个部分。我们可以访问每个部分的内容、类型、大小等信息,以便根据需要进行处理。 另外,nio-multipart还可以处理大文件上传,并在处理过程中节省内存。它使用NIO的特性,将请求数据分成一系列块,逐个处理而不是将整个文件加载到内存中。这种方式可以减少内存使用量,并提高性能和吞吐量。 综上所述,nio-multipart是一个用于处理基于NIO的多部分请求的依赖库。它简化了多部分请求的解析和处理过程,并提供了高效处理大文件上传的方法。它可以在Web应用程序中广泛使用,提高开发效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值