阅读nio文档
This commit is contained in:
126
java se/nio.md
126
java se/nio.md
@@ -251,3 +251,129 @@ public class CopyFile {
|
||||
```
|
||||
|
||||
在上述示例中,通过`channel.read(buffer)`的返回值来判断是否已经读取到文件末尾,如果返回值为-1,那么代表文件读取已经完成。
|
||||
|
||||
## File Lock
|
||||
可以针对整个文件或文件的部分进行加锁。文件锁分为独占锁和共享锁,如果获取了独占锁,那么其他进程将无法获取同一文件加锁;如果获取了共享锁,那么其他进程也可以获取同一文件的共享锁,但是无法获取到独占锁。
|
||||
|
||||
### 对文件进行上锁
|
||||
在获取锁时,需要在FileChannel上调用lock方法:
|
||||
```java
|
||||
RandomAccessFile raf = new RandomAccessFile("usefilelocks.txt", "rw");
|
||||
FileChannel fc = raf.getChannel();
|
||||
FileLock lock = fc.lock(start, end, false);
|
||||
```
|
||||
释放锁方法如下所示:
|
||||
```java
|
||||
lock.release();
|
||||
```
|
||||
## Network和异步IO
|
||||
通过异步io,可以在没有blocking的情况下读取和写入数据,在通常情况下,调用read方法会一直阻塞到数据可以被读取,而write方法会一直阻塞到数据可以被写入。
|
||||
|
||||
异步IO通过注册io事件来实现,当例如新的可读数据、新的网络连接到来时,系统会根据注册的io时间监听来发送消息提醒。
|
||||
|
||||
异步io的好处是,可以在同一线程内处理大量的io操作。在传统的io操作中,如果要处理大量io操作,通常需要轮询、创建大量线程来针对io操作进行处理。
|
||||
- 轮询:对io请求进行排队,处理完一个io请求后再处理别的请求
|
||||
- 创建大量线程:针对每个io请求,为其创建一个线程进行处理
|
||||
|
||||
通过nio,可以通过单个线程来监听多个channel的io事件,无需轮询也无需额外的事件。
|
||||
|
||||
### Selector
|
||||
nio的核心对象为selector,将channel及其感兴趣的io事件类型注册到selector后,如果io事件触发,那么`selector.select`方法将会返回对应的SelectionKey。
|
||||
|
||||
Selector创建如下:
|
||||
|
||||
```java
|
||||
Selector selector = Selector.open();
|
||||
```
|
||||
|
||||
### 开启ServerSocketChannel
|
||||
为了接收外部连接,需要一个ServerSocketChannel,创建ServerSocketChannel并配置对应ServerSocket的示例如下所示:
|
||||
```java
|
||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
||||
ssc.configureBlocking(false);
|
||||
ServerSocket ss = ssc.socket();
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(ports[i]);
|
||||
ss.bind(address);
|
||||
```
|
||||
|
||||
### Selection keys
|
||||
在创建完SelectableChannel之后,需要将channel注册到selector,可以调用`channel.register`来执行注册操作:
|
||||
```java
|
||||
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
|
||||
```
|
||||
|
||||
上述方法为ServerSocketChannel注册了OP_ACCEPT的事件监听,OP_ACCEPT事件当新连接到来时将会被触发,OP_ACCEPT是适用于ServerSocketChannel的唯一io事件类型。
|
||||
|
||||
register方法的返回值SelectionKey代表channel和selector的注册关系,当io事件触发时,selector也会返回事件关联的SelectionKey。
|
||||
|
||||
除此之外,SelectionKey也可以被用于取消channel对selector的注册。
|
||||
|
||||
### inner loop
|
||||
在向selector注册完channel之后,会进入到selector的循环
|
||||
```java
|
||||
while (true) {
|
||||
selector.select();
|
||||
|
||||
Set<SelectionKey> selectedKeys = selector.selectedKeys();
|
||||
Iterator<SelectionKey> it = selectedKeys.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
SelectionKey key = it.next();
|
||||
// ... deal with I/O event ...
|
||||
}
|
||||
}
|
||||
```
|
||||
在调用`selector.select`方法时,改方法会阻塞,直到有至少一个注册的io事件被触发。`selector.select`会返回触发事件的个数。
|
||||
|
||||
`select.selectedKeys()`方法则是会返回被触发事件关联的SelectionKey集合。
|
||||
|
||||
对于每个SelectionKey,需要通过`key.readyOps()`来判断事件的类型,并以此对其进行处理。
|
||||
|
||||
### 为新连接注册
|
||||
当新连接到来后,需要将新连接注册到selector中
|
||||
|
||||
```java
|
||||
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
|
||||
SocketChannel sc = ssc.accept();
|
||||
|
||||
sc.configureBlocking(false);
|
||||
// 监听新连接的READ事件类型
|
||||
sc.register(selector, SelectionKey.OP_READ);
|
||||
```
|
||||
|
||||
### remove SelectionKey
|
||||
在完成对io事件的处理之后,必须要将SelectionKey从selectedKeys之中移除,否则selectionKey将会被一直作为活跃的io事件
|
||||
```java
|
||||
it.remove();
|
||||
```
|
||||
|
||||
### 新连接有可读数据
|
||||
当注册的新连接传来可读数据之后,可读数据处理方式如下:
|
||||
```java
|
||||
else if ((key.readyOps() & SelectionKey.OP_READ)
|
||||
== SelectionKey.OP_READ) {
|
||||
|
||||
// Read the data
|
||||
SocketChannel sc = (SocketChannel) key.channel();
|
||||
```
|
||||
## CharsetEncoder/CharsetDecoder
|
||||
通过`CharsetEncoder/CharsetDecoder`,可以进行`CharBuffer`和`ByteBuffer`之间的转化。
|
||||
|
||||
```java
|
||||
// 获取字符集
|
||||
Charset latin1 = Charset.forName("ISO-8859-1");
|
||||
|
||||
// 通过字符集创建encoder/decoder
|
||||
CharsetDecoder decoder = latin1.newDecoder();
|
||||
CharsetEncoder encoder = latin1.newEncoder();
|
||||
|
||||
CharBuffer cb = decoder.decode(inputData);
|
||||
|
||||
ByteBuffer outputData = encoder.encode(cb);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user