Java NIO

简介:

Java是非常繁杂的语言, 比如IO就是典型的代表...

Java IO

首先1.0, 是基于8位字节流的InputStream和OutputStream系列 
然后是1.1, 是基于16位的字符流(unicode)的Reader和Writer系列

下表是对应关系, 其中InputStreamReader和OutputStreamWriter, 起到两个系列之间的适配作用

当然实际的继承关系比这个复杂的多, 通过装饰模式, 产生各种IO类, 非常繁杂

image

 

Java NIO, New IO

从1.4开始, Java提供new IO 
其实在new IO中主要两个提升 
a, buffer和channel 
解决小块数据传输带来的效率问题, 引入buffer数据结构, 可以批量传输以提高效率(这样更符合底层数据传输的方式), 一个挖煤的比喻, 从挖一铲运一铲到挖满一卡车再运出来

b, 对于socket channel加入非阻塞方式

 

Buffer

提供一种支持丰富操作的数据结构, 同时虽然对于所有的类型(除bool类型)都有相应的buffer, 但是只有ByteBuffer可以直接被channel读取, 其余的都需要在放到channel之前做类型转换

image

数据结构

image

支持操作

image

下图以FileChannel为例子, 
首先Channel只能接收ByteBuffer作为write/read的参数 
对于其他的buffer必须做类型转换, 尤其对于CharBuffer需要考虑charset的encode/decode

image

 

Channel

管道很形象, 就是连接发送端和接收端之间的媒介 
其实就是对于传统socket或file接口针对ByteBuffer的封装

I/O可以分为广义的两大类别:File I/O和Stream I/O 
所以对应的, Channel分为两类, FileChannel和Socket相关channel(SocketChannel、ServerSocketChannel和 DatagramChannel)

FileChannel

FileChannel类可以实现常用的read,write以及scatter/gather操作(对于多个buffer的批处理), 同时它也提供了很多专用于文件的新方法. 
文件通道总是阻塞式的, 因为现代操作系统都有复杂的缓存和预取机制, 所以本地磁盘I/O操作延迟很少

FileChannel对象不能直接创建。一个FileChannel实例只能通过在一个打开的file对象(RandomAccessFile、FileInputStream或 FileOutputStream)上调用getChannel( )方法获取

FileChannel对象是线程安全(thread-safe)

1.4中, Java通过FileChannel实现了文件锁(之前Java不支持文件锁), 但是这是进程级别锁, 相同进程中不同线程无法通过文件锁进行互斥

SocketChannel

新的socket通道类可以运行非阻塞模式, 这个大大提升了Java IO的性能, 之前只能使用多线程阻塞的方式来处理并发, 但线程调度的开销也很高尤其当维护大量线程的时候

全部socket通道类(DatagramChannel、SocketChannel和ServerSocketChannel), 分别对应于java.net中的(Socket、ServerSocket和DatagramSocket), 并且Channel其实就是对他们的封装

ServerSocketChannel

ByteBuffer buffer = ByteBuffer.wrap (GREETING.getBytes( )); 
ServerSocketChannel ssc = ServerSocketChannel.open( ); 
ssc.socket( ).bind (new InetSocketAddress (port)); 
ssc.configureBlocking (false); //non-blocking

while (true) { 
    System.out.println ("Waiting for connections"); 
    SocketChannel sc = ssc.accept( ); //不会blocking直接返回
    if (sc == null) { 
        // no connections, snooze a while 
        Thread.sleep (2000); } 
    else { 
        System.out.println ("Incoming connection from: " + sc.socket().getRemoteSocketAddress( ));  
        buffer.rewind( ); 
        sc.write (buffer); 
        sc.close( ); } } 

 

SocketChannel

InetSocketAddress addr = new InetSocketAddress (host, port); 
SocketChannel sc = SocketChannel.open( ); 
sc.configureBlocking (false); //设置non-blocking
sc.connect (addr); //不会阻塞等待
while ( ! sc.finishConnect( )) { 
    doSomethingElse( ); } 
doSomethingWithChannel (sc); sc.close( ); 

从上面两个例子可以看出channel的使用, 其实和原来的API没有很大的不同, 关键就是支持non-blocking方式

 

Selector

当然还需要selector, 不然非阻塞意义不大, 象C/C++中的select, poll

Selector selector = Selector.open( ); 
channel1.register (selector, SelectionKey.OP_READ); 
channel2.register (selector, SelectionKey.OP_WRITE); 
channel3.register (selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); 
// Wait up to 10 seconds for a channel to become ready 
readyCount = selector.select (10000); 

只有继承SelectableChannel的Channel类才可以被注册到Selector对象上, 所以FileChannel对象不是可选择的, 而所有SocketChannel都是可选择的

SelectionKey

代表了Selector和SelectableChannel的注册关系 
key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定 
key.channel(); // 返回该SelectionKey对应的channel 
key.selector(); // 返回该SelectionKey对应的Selector 
key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask 
key.readyOps(); //返回一个bit mask,代表在相应channel上可以进行的IO操作

package java.nio.channels;
//ops, selector所关心的通道操作,读(read),写(write),连接(connect)和接受(accept)
public abstract SelectionKey register (Selector sel, int ops) throws ClosedChannelException; 

public abstract class SelectionKey { 
    public static final int OP_READ; 
    public static final int OP_WRITE; 
    public static final int OP_CONNECT; 
    public static final int OP_ACCEPT; 
    public abstract SelectableChannel channel( ); 
    public abstract Selector selector( ); 
    public abstract void cancel( ); 
    public abstract boolean isValid( ); 
    public abstract int interestOps( ); 
    public abstract void interestOps (int ops); 
    public abstract int readyOps( ); 
    public final boolean isReadable( ); 
    public final boolean isWritable( );
    public final boolean isConnectable( );
    public final boolean isAcceptable( ); 
    public final Object attach (Object ob) 
    public final Object attachment( ) } 

使用的代码

// Allocate an unbound server socket channel 
ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
// Get the associated ServerSocket to bind it with ServerSocket 
serverSocket = serverChannel.socket(); 
// Create a new Selector for use below Selector 
selector = Selector.open(); 
// Set the port the server channel will listen to 
serverSocket.bind(new InetSocketAddress(port)); 
// Set nonblocking mode for the listening socket 
serverChannel.configureBlocking(false);
// Register the ServerSocketChannel with the Selector 
serverChannel.register(selector, SelectionKey.OP_ACCEPT); //关注accept

while (true) { 
// This may block for a long time. Upon returning, the 
// selected set contains keys of the ready channels. 
int n = selector.select(); 
if (n == 0) { 
    continue; // nothing to do
}
// Get an iterator over the set of selected keys 
Iterator it = selector.selectedKeys().iterator(); 
// Look at each key in the selected set 
while (it.hasNext()) { 
    SelectionKey key = (SelectionKey) it.next(); 
    // Is a new connection coming in? 
    if (key.isAcceptable()) { 
        ServerSocketChannel server = (ServerSocketChannel) key.channel(); 
        SocketChannel channel = server.accept(); 
        registerChannel(selector, channel, SelectionKey.OP_READ); //Accept后设置成关注Read
        sayHello(channel); } 
    // Is there data to read on this channel? 
    if (key.isReadable()) { 
        readDataFromSocket(key); } 
} } } 


本文章摘自博客园,原文发布日期:2013-10-10
目录
相关文章
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
17天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
31 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
88 2
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
120 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
74 0
|
4月前
|
安全 Java
【Java】已解决java.nio.channels.OverlappingFileLockException异常
【Java】已解决java.nio.channels.OverlappingFileLockException异常
132 1
|
4月前
|
Java
【Java】已解决java.nio.channels.ClosedChannelException异常
【Java】已解决java.nio.channels.ClosedChannelException异常
414 1
下一篇
无影云桌面