java中attachement什么意思_Java核心-基础IO

Java核心-基础IO

【Java核心-基础】IO

.

Java 的 IO 方式大致可分为 3 类:BIO、NIO、NIO 2(AIO)

这 3 类 IO 方式在 同步/异步 和 阻塞/非阻塞 方面有明显区别。

同步 vs 异步

同步:后续任务必须等当前调用返回后再执行。

异步:后续任务不需要等待当前调用返回,依靠事件、回调等机制实现任务间次关系。

阻塞 vs 非阻塞

阻塞:执行阻塞操作时,当前线程会处于阻塞状态,无法执行其它任务,只有条件就绪后才能继续。

非阻塞:不管操作是否结束,当前线程直接返回,由后台其它线程继续处理。

4c84e1937fe5b73caf9549f52d89eb20.png

BIO 指传统的 java.io 包,也包括 java.net 下的部分API(如,Socket、ServerSocket、HttpURLConnection)。

BIO 基于流模型,以同步、阻塞的方式交互(B:Blocking)。

优点:简单、直观。

缺点:IO 效率 和 扩展性 存在局限性,容易成为性能瓶颈。

InputStream / OutputStream 用于读写 字节

Reader / Writer 增加了编解码功能,用于读写 字符

BufferedInputStream / BufferedOutputStream 带缓存区,对批量数据进行一次操作,可以减少对磁盘等硬件的读写频率,提高IO效率

写数据后需要 flush

Closeable 接口提供的 close() 方法可以释放相关资源

如,释放 FileInputStream 所获取的文件描述符(FileDescriptor)

可以利用 try-with-resources 和 try-finally 机制来确保调用了 close()方法

Java 1.4 引入了 NIO

提供了 Channel、Selector、Buffer 等机制,可以构建多路复用、同步非阻塞的IO程序(N:New、Non-Blocking)。

它提供了更接近操作系统底层的高性能数据操作方式。

JDK 的这部分功能在不同操作系统上实现有较大不同,应在真实的运行环境上测试。如,开发环境是 Windows,部署环境是 Linux,则应以 Linux 环境的调试结果为准。

Java 1.7 引入了 NIO 2(AIO)

提供了异步非阻塞的IO方式(A:Asynchronous)。

缺点:单个请求中数据量较大时,对后续事件的响应会被延迟。所以多路复用适用于大量请求大小有限的场景。

Buffer 是高效的数据容器

除 boolean 外,所有原始数据类型都有相应的 Buffer 实现。

Channel 用于支持 批量 式 IO

类似 Linux 上的文件描述符,比 File、Socket 更接近操作系统底层。

Channel 可以充分利用操作系统底层机制,获得特定场景的性能优化。如,DMA(Direct Memory Access)。

Selector 用于支持 多路复用

它可以监测到注册在 Selector 上的多个 Channel 中,是否有 Channel 处于就绪状态,实现单线程对多 Channel 的高效管理。

针对不同操作系统,Selector 的实现了不同;Linux 上依赖于 Epoll;Windows 上依赖于 iocp

此处以 Client-Server Socket 通信为例来说明 NIO 的应用差异。

用 BIO 实现

针对每个来自 Client 的请求,都创建一个对应线程执行,或交由线程池处理。

缺点:扩展性差。大量客户端请求时,产生大量连接,服务端对每个连接的处理需要线程上下文切换,开销过高。

67a9d6ab6362acdb61591d5bab1d2f47.png

Java代码

dbf134e2322b949e5a487f44b1f455dd.png

ServerSocket serverSocket = new ServerSocket(80);

while (true) {

Socket socket = serverSocket.accept();

Thread requestHandler = new Thread(()->{

// 处理来自客户端的请求(socket)

});

requestHandler.start();

}

用 NIO 实现

每一个来自 Client 的请求都被汇聚到 Selector,用单线程轮询定位就绪的 Channel,再处理相应的请求。

Selector 类似于一个 调度员

同步:每个准备好的 channel 处理是依次进行的;

非阻塞:不需要每个连接(channel)都有一个对应的线程在等它就绪 。

只有 select 阶段是阻塞的,可以避免大量客户端连接导致线程频繁切换的问题。

acfd3feaaa6a0b1adef8f28d7990d4c3.png

示例代码只注册了一个 Channel。

真实应用中一般会创建 多个 Channel,注册到同一个 Selector,也就是 多路复用。

为了避免单个 Selector (单线程)执行监听任务成为瓶颈,也可以尝试用 多个 Selector。

Java代码

f6f3bdbc11b6de84c872df648617432f.png

try (Selector selector = Selector.open();

ServerSocketChannel socketChannel = ServerSocketChannel.open()) {

socketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 80));

socketChannel.configureBlocking(false);

// 注册到 Selector,并说明关注点(accept)

socketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

selector.select(); // 等待就绪的 Channel(这是阻塞操作)

Set selectionKeys = selector.selectedKeys();

Iterator iter = selectionKeys.iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

// 处理请求

ServerSocketChannel channel = (ServerSocketChannel)key.channel();

...

iter.remove();

}

}

} catch (IOException e) {

// 处理异常

}

用 AIO 实现

这只是个简单的示例,真实应用中会更复杂

Java代码

a863dd72dcf7b67271f76918c929ac8f.png

try {

AsynchronousServerSocketChannel asyncChannel

= AsynchronousServerSocketChannel.open();

asyncChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 80));

asyncChannel.accept(null,

new CompletionHandler() {

@Override

public void completed(AsynchronousSocketChannel result,

Void attachment) {

// 接收下一次连接

asyncChannel.accept(null, this);

// 处理本次连接

...

}

@Override

public void failed(Throwable exc, Void attachement) {

// 处理连接失败的情况

}

})

} catch (IOException e) {

// 处理异常

}

Java核心-基础IO相关教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值