JAVA中的NIO

标准的IO是基于字节流和字符流进行操作的,而JAVA中的NIO是基于Channel和Buffer进行操作的。

传统IO

graph TB;
字节流 --> InputStream;
字节流 --> OutputStream;
字符流 --> Reader;
字符流 --> Writer;

NIO

graph TB;
A[Channel] --> B[Buffer..];
C[Channel] --> D[Buffer..];
E[Channel] --> F[Buffer..];

核心模块

NIO主要有三个核心部分:Selector、Channel、Buffer

数据总是从Channel读取到Buffer或者从Buffer写入到Channel中。

Selector可以监听多个Channel的多个事件。

graph TB;
Selector --> A[Channel];
Selector --> B[Channel];
Selector --> C[Channel];
A --> E1[Event...];
B --> E2[Event...];
C --> E3[Event...];

传统的IO与Channel的区别

1.传统的IO是BIO的,而Channel是NIO的。

*当流调用了read()、write()方法后会一直阻塞线程直到数据被读取或写入完毕。

2.传统IO流是单向的,而Channel是双向的。


Channel

FileChannel:从文件中进行读取

DatagramChannel:可以通过UDP协议在网络中进行数据的传输

SocketChannel:可以通过TCP协议在网络中进行数据的传输

ServerSocketChannel:可以作为一个服务器监听连接

Channel通用API:

read(buffer):将数据从Channel读取到Buffer中,读取完毕返回-1。

read(buffer []):将数据从Channel读取到多个Buffer中,仅当第一个Buffer被写满后往第二个Buffer中进行写入。

write(buffer):将Buffer中的数据写入到Channel中。

write(buffer[]):将多个Buffer中的数据写入到Channel中,仅当第一个Buffer中的数据被读取完毕后再从第二个Buffer中进行读取。

register(selector,interest):将Channel注册到Selector中,同时需要向Selector传递要监听此Channel的事件类型(注册到Selector中的Channel一定要非阻塞的)

configureBlocking(boolean):设置Channel是否为阻塞。

transferFrom(position,count,channel):将其他Channel中的数据传输到当前Channel中。

transferTo(position,count,channel):将当前Channel中的数据传输到其他Channel中。

SocketChannel API

open()静态方法:创建SocketChannel。

connect(new InetSocketAddress(port))方法:连接服务器。

finishConnect()方法:判断是否已经与服务器建立连接。

ServerSocketChannel API

open()静态方法:创建ServerSocketChannel。

accept()方法:该方法会一直阻塞线程直到有新连接到达。

阻塞式与非阻塞式Channel

正常情况下Channel都是阻塞的,只有当调用了configureBlocking(false)方法时Channel才为非阻塞。

阻塞式Channel的connect()、accept()、read()、write()方法都会阻塞线程,直到处理完毕。

非阻塞式Channel的connect()、accept()、read()、write()方法都是异步的。

*当调用了非阻塞式Channel的connect()方法后,需要使用finishConnect()方法判断是否已经与服务器建立连接。

*当调用了非阻塞式Channel的accept()方法后,需要根据方法的返回值是否为NULL判断是否接收到新的连接。

*当调用了非阻塞式Channel的read()方法后,需要根据方法的返回值是否大于0判断是否有读取到数据。

*在使用非阻塞式Channel的write()方法时,需要借助while循环与hasRemaining()方法保证buffer中的内容被全部写入。

*FileChannel一定是阻塞的。

示例

public void testFileChannel() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile(new File("F:\\笔记\\nginx.txt"), "rw");
FileChannel fileChannel = randomAccessFile.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(64);
int count = fileChannel.read(byteBuffer);
while (count != -1) {
byteBuffer.flip();
System.out.println(new String(Arrays.copyOfRange(byteBuffer.array(),0,byteBuffer.limit()),Charset.forName("UTF-8")));
byteBuffer.clear();
count = fileChannel.read(byteBuffer);
}
}

Buffer

Buffer是一块可以进行读写操作的内存(顺序存储结构)

ByteBuffer:基于Byte类型进行存储

CharBuffer:基于Char类型进行存储

DoubleBuffer:基于Double类型进行存储

FloatBuffer:基于Float类型进行存储

IntBuffer:基于Int类型进行存储

LongBuffer:基于Long类型进行存储

ShortBuffer:基于Short类型进行存储

Buffer的内部结构

1.capacity:表示buffer的容量

2.position:表示当前的位置(从0开始,最大值为capacity-1)

3.limit:在写模式中表示可以写入的个数(与capacity一样),在读模式中表示可以读取的个数。

从写模式转换成读模式

limit设置为position+1,position设置为0。

从读模式转换成写模式

limit设置为capacity,position设置为0。

往Buffer中写数据

1.将数据从Channel读取到Buffer中。

2.使用Buffer的put()方法。

从Buffer中读数据

1.将Buffer中的数据写入到Channel中。

2.使用Buffer的get()方法

Buffer通用API:

allocate(size)静态静态:初始化一个Buffer。

flip():将buffer从写模式转换成读模式。

array():将Buffer中的内容转换成数组(不受limit控制)

get():获取Buffer中的内容。

hasRemaining():判断Buffer中是否还有未读的元素(limit - (postion+1) )

rewind():将positon设置为0。

clear():将limit设置为capacity,position设置为0。

compact():将所有未读的元素移动到Buffer的起始处,position指向最后一个未读的元素的下一位,limit设置为capacity。

*clear()和compact()方法都可以理解成将Buffer从读模式转换成写模式,区别在于compact()方法会保留未读取的元素。

mark():在当前position处打一个标记。

reset():将position恢复到标记处。

Selector

Selector用于监听多个Channel的多个事件(单线程)

graph TB;
Selector --> A[Channel];
Selector --> B[Channel];
Selector --> C[Channel];
A --> E1[connect];
B --> E2[accept];
C --> E3[connect];
C --> E4[read];

Channel的事件类型

1.连接就绪:当SocketChannel、DatagramChannel成功与服务器建立连接时将会触发连接就绪事件。

2.接收就绪:当有连接到达服务器时将会触发接收就绪事件。

3.读就绪:当SocketChannel、DatagramChannel有数据可读时将会触发读就绪事件。

4.写就绪:当SocketChannel、DatagramChannel可以进行数据写入时将会触发写就绪事件。

SelectionKey

SelectionKey用于存储Selector与Channel之间的相关信息。

SelectionKey中提供了四个常量分别代表Channel的事件类型。

SelectionKey.OP_CONNECT

SelectionKey.OP_ACCEPT

SelectionKey.OP_READ

SelectionKey.OP_WRITE

SelectableChannel提供的register(selector,interest)方法用于将Channel注册到Selector中,同时需要向Selector传递要监听此Channel的事件类型,当要监听的事件类型不止一个时可以使用或运算,当将Channel注册到Selector后会返回SelectionKey实例,用于存储Selector与此Channel之间的相关信息。

SelectionKey API:

interestOps()方法:返回Selector监听此Channel的事件类型。

readyOps()方法:返回此Channel目前就绪的事件。

isAcceptable():判断Channel是否接收就绪。

isConnectable():判断Channel是否连接就绪。

isReadable():判断Channel是否读就绪。

isWriteable():判断Channel是否写就绪。

channel():返回具体的Channel实例。

selector():返回Selector实例。

attach():往SelectionKey中添加一个附加对象。

attachment():返回保存在SelectionKey中的附加对象。

Selector API:

open()静态方法:创建一个Selector。

select()方法:该方法会一直阻塞线程直到所监听的Channel有事件就绪,返回就绪的Channel个数(只会返回新就绪的Channel个数)

selectedKeys()方法:返回就绪的Channel对应的SelectionKey。

*当Channel就绪的事件处理完毕后,需要手动删除SelectionKey集合中该Channel对应的SelectionKey,当该Channel再次有事件就绪时会自动加入到Selectionkey集合中。

非阻塞式Channel与Selector

非阻塞式Channel一般与Selector配合使用

当Selector监听到ServerSocketChannel接收就绪时,那么此时可以立即调用ServerSocketChannel的accept()方法获取新连接。

当Selector监听到SocketChannel读就绪时,那么此时可以立即调用SocketChannel的read()方法进行数据的读取。

非阻塞式服务器

/**
* @Author: Zhuang HaoTang
* @Date: 2019/10/26 16:35
* @Description:
*/
public class Server { public void start() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = createNIOServerSocketChannel();
System.out.println("start nio server and bind port 8888");
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
int ready = selector.select();
while (ready > 0) {
System.out.println("ready channel count " + ready);
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
for (Iterator<SelectionKey> iterator = selectionKeySet.iterator(); iterator.hasNext(); ) {
SelectionKey selectionKey = iterator.next();
if (selectionKey.isAcceptable()) {
System.out.println("acceptable");
acceptHandler(selectionKey);
} else if (selectionKey.isReadable()) {
System.out.println("readable");
readHandler(selectionKey);
}
iterator.remove();
}
ready = selector.select();
}
} private ServerSocketChannel createNIOServerSocketChannel() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
serverSocketChannel.configureBlocking(false);
return serverSocketChannel;
} private void acceptHandler(SelectionKey selectionKey) throws IOException {
Selector selector = selectionKey.selector();
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("accept client connection " + socketChannel.getLocalAddress());
} private void readHandler(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
int num = socketChannel.read(byteBuffer);
if(num == -1){ // 连接已断开
System.out.println("client "+socketChannel.getLocalAddress() + " disconnection");
socketChannel.close();
return;
}
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
byte b = byteBuffer.get();
System.out.println((char) b);
}
} public static void main(String[] args) throws IOException {
Server server = new Server();
server.start();
} }

*一个Channel不会同时有多个事件就绪,以事件为单位。

*当客户端断开连接,那么将会触发读就绪,并且channel的read()方法返回-1,表示连接已断开,服务器应该要做出处理,关闭这个连接。

客户端

/**
* @Auther: Zhuang HaoTang
* @Date: 2019/10/26 16:36
* @Description:
*/
public class Client { public static void main(String[] args) throws IOException, InterruptedException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(),8888)); String message = "today is sunday";
ByteBuffer byteBuffer = ByteBuffer.allocate(message.getBytes().length);
byteBuffer.put(message.getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
Thread.sleep(5000);
} }

运行结果


Reactor模式

Reactor有三种模式

1.Reactor单线程模式
2.Reactor多线程模式
3.主从Reactor多线程模式

*Reactor模式是在NIO下实现的。

Reactor单线程模式

1.单线程的事件分化器,同时这个线程需要处理接收、读、写就绪事件。

/**
* @Author: Zhuang HaoTang
* @Date: 2019/10/26 16:35
* @Description:
*/
public class ReactorSingleThreadServer { private void start() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = createNIOServerSocketChannel();
System.out.println("start nio server and bind port 8888");
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
int ready = selector.select();
while (ready > 0) {
System.out.println("ready channel count " + ready);
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
for (Iterator<SelectionKey> iterator = selectionKeySet.iterator(); iterator.hasNext(); ) {
SelectionKey selectionKey = iterator.next();
if (selectionKey.isAcceptable()) {
System.out.println("acceptable");
acceptHandler(selectionKey);
} else if (selectionKey.isReadable()) {
System.out.println("readable");
readHandler(selectionKey);
}
iterator.remove();
}
ready = selector.select();
}
} private ServerSocketChannel createNIOServerSocketChannel() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
serverSocketChannel.configureBlocking(false);
return serverSocketChannel;
} private void acceptHandler(SelectionKey selectionKey) throws IOException {
Selector selector = selectionKey.selector();
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("accept client connection " + socketChannel.getLocalAddress());
} private void readHandler(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
int num = socketChannel.read(byteBuffer);
if (num == -1) {
System.out.println("client " + socketChannel.getLocalAddress() + " disconnection");
socketChannel.close();
return;
}
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
byte b = byteBuffer.get();
System.out.println((char) b);
}
} public static void main(String[] args) throws IOException {
ReactorSingleThreadServer server = new ReactorSingleThreadServer();
server.start();
} }

Reactor多线程模式

1.单线程的事件分发器。

2.具体事件类型的Handler线程池(针对读写就绪事件)

3.业务线程池。

/**
* @Author: Zhuang HaoTang
* @Date: 2019-10-28 17:00
* @Description:
*/
public class ReactorMultiThreadServer { private ThreadPoolExecutor eventHandlerPool = new ThreadPoolExecutor(10, 50, 2, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(200), new ThreadPoolExecutor.CallerRunsPolicy()); private void start() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = createNIOServerSocketChannel();
System.out.println("start nio server and bind port 8888");
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
selector.select();
for (;;) {
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
for (Iterator<SelectionKey> iterator = selectionKeySet.iterator(); iterator.hasNext(); ) {
final SelectionKey selectionKey = iterator.next();
if (selectionKey.isAcceptable()) {
System.out.println("acceptable");
acceptHandler(selectionKey); // 单线程同步处理接收就绪
} else if (selectionKey.isReadable()) {
System.out.println("readable");
eventHandlerPool.submit(new Runnable() {
@Override
public void run() {
readHandler(selectionKey);
}
});
}
iterator.remove();
}
selector.select();
}
} private ServerSocketChannel createNIOServerSocketChannel() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
serverSocketChannel.configureBlocking(false);
return serverSocketChannel;
} private void acceptHandler(SelectionKey selectionKey) throws IOException {
Selector selector = selectionKey.selector();
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("accept client connection " + socketChannel.getLocalAddress());
}
} private void readHandler(SelectionKey selectionKey) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
try {
int num = socketChannel.read(byteBuffer);
if (num == -1) {
System.out.println("client " + socketChannel.getLocalAddress() + " disconnection");
socketChannel.close(); // 底层有些逻辑
return;
}
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
byte b = byteBuffer.get();
System.out.println((char) b);
}
} catch (Exception e) {
System.out.println("由于连接关闭导致并发线程读取异常");
}
} public static void main(String[] args) throws IOException {
ReactorMultiThreadServer reactorServer = new ReactorMultiThreadServer();
reactorServer.start();
} }

主从Reactor多线程模式

1.使用两个单线程的事件分发器。

第一个事件分发器只负责监听ServerSocketChannel的接收就绪事件,同时ServerSocketChannel接收到的连接要注册到第二个事件分发器中。
第二个事件分发器只负责监听SocketChannel的读、写就绪事件。

2.具体事件类型的Handler线程池(针对读写就绪事件)

3.业务线程池。

/**
* @Author: Zhuang HaoTang
* @Date: 2019-10-28 17:00
* @Description:
*/
public class MainSubReactorMultiThreadServer { private ThreadPoolExecutor eventHandlerPool = new ThreadPoolExecutor(10, 50, 2, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(200), new ThreadPoolExecutor.CallerRunsPolicy()); private void start() throws IOException {
final Selector mainSelector = Selector.open();
final Selector subSelector = Selector.open(); new Thread(new Runnable() {
@Override
public void run() {
try {
startMainSelector(mainSelector, subSelector);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
try {
startSubSelector(subSelector);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start(); } /**
* 第一个事件分发器,用于监听ServerSocketChannel的接收就绪事件
*/
private void startMainSelector(Selector mainSelector, final Selector subSelector) throws IOException {
ServerSocketChannel serverSocketChannel = createNIOServerSocketChannel();
System.out.println("start nio server and bind port 8888");
serverSocketChannel.register(mainSelector, SelectionKey.OP_ACCEPT);
mainSelector.select();
for (; ; ) {
Set<SelectionKey> selectionKeySet = mainSelector.selectedKeys();
SelectionKey selectionKey = Iterables.getOnlyElement(selectionKeySet);
if (selectionKey.isAcceptable()) {
System.out.println("acceptable");
acceptHandler(selectionKey, subSelector); // 单线程同步处理接收就绪
selectionKeySet.clear();
}
mainSelector.select();
}
} /**
* 第二个事件分发器,用于监听SockChannel的读写就绪事件
*/
private void startSubSelector(Selector subSelector) throws IOException {
subSelector.select();
for (; ; ) {
Set<SelectionKey> selectionKeySet = subSelector.selectedKeys();
for (Iterator<SelectionKey> iterator = selectionKeySet.iterator(); iterator.hasNext(); ) {
final SelectionKey selectionKey = iterator.next();
if (selectionKey.isReadable()) {
System.out.println("readable");
eventHandlerPool.submit(new Runnable() {
@Override
public void run() {
readHandler(selectionKey);
}
});
iterator.remove();
}
}
subSelector.select();
}
} private ServerSocketChannel createNIOServerSocketChannel() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
serverSocketChannel.configureBlocking(false);
return serverSocketChannel;
} private void acceptHandler(SelectionKey selectionKey, Selector subSelector) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
socketChannel.configureBlocking(false);
subSelector.wakeup(); // 往Selector注册Channel时,Selector要处于非阻塞状态
socketChannel.register(subSelector, SelectionKey.OP_READ);
System.out.println("accept client connection " + socketChannel.getLocalAddress() + " and register to subSelector");
}
} private void readHandler(SelectionKey selectionKey) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
try {
int num = socketChannel.read(byteBuffer);
if (num == -1) {
System.out.println("client " + socketChannel.getLocalAddress() + " disconnection");
socketChannel.close(); // 底层有些逻辑
return;
}
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
byte b = byteBuffer.get();
System.out.println((char) b);
}
} catch (Exception e) {
System.out.println("由于连接关闭导致并发线程读取异常");
}
} public static void main(String[] args) throws IOException {
MainSubReactorMultiThreadServer reactorServer = new MainSubReactorMultiThreadServer();
reactorServer.start();
} }

通用客户端

/**
* @Author: Zhuang HaoTang
* @Date: 2019/10/26 16:36
* @Description:
*/
public class Client { public static void main(String[] args) throws IOException, InterruptedException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
String message = "today is sunday";
ByteBuffer byteBuffer = ByteBuffer.allocate(message.getBytes().length);
byteBuffer.put(message.getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
Thread.sleep(5000);
ByteBuffer byteBuffer1 = ByteBuffer.allocate("wo".getBytes().length).put("wo".getBytes());
byteBuffer1.flip();
socketChannel.write(byteBuffer1); ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
while (true) {
socketChannel.read(receiveBuffer);
receiveBuffer.flip();
while (receiveBuffer.hasRemaining()) {
System.out.println((char)receiveBuffer.get());
}
receiveBuffer.clear();
}
} }

*主线程不需要等待具体事件类型的Handler处理完毕,直接异步返回,那么将会导致事件重复就绪,程序做出相应的控制即可。

*当channel有数据可读时,将会触发读就绪,那么主线程将会不停的向线程池提交任务,直到某个线程读取完毕,此时将会停止读就绪,其他线程读取到的个数为0。

*当客户端断开连接时,将会触发读就绪,那么主线程将会不停的向线程池提交任务,直到某个线程关闭连接,此时将会停止读就绪

一般不会直接去使用JAVA NIO,只是通过JAVA NIO学习他的设计思想,如果要想搭建NIO服务器那么应该使用Netty等NIO框架。


关于BIO和NIO的选择

BIO即同步并阻塞,线程会进入阻塞状态,如果并发连接数只有几百,那么创建几百个线程去处理是没有任何问题的,这种方式更加简单高效。

但是如果并发连接数达到几万,那么显然创建几万个线程去处理是不可行的,系统承受不了这个负荷,此时应该使用NIO,即同步非阻塞,利用更少的线程去做更多的事情。

JAVA NIO就是使用NIO(同步非阻塞),使用IO多路复用的Select模型。

*不管客户端有多少个并发连接和请求,服务端总是可以利用更少的线程去处理(单线程事件分发器 和 具体事件类型的Handler线程池)

JAVA中的NIO (New IO)的更多相关文章

  1. java中的NIO和IO到底是什么区别?20个问题告诉你答案

    摘要:NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多. 本文分享自华为云社区<jav ...

  2. Java中的NIO和IO的对比分析

    总的来说,java中的IO和NIO主要有三点区别: IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器(Selectors) 1.面向流与面向缓冲 Java NIO和IO之间第一个最大的 ...

  3. Java中的NIO及IO

    1.概述 Java NIO(New IO) 是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同, ...

  4. Java中的NIO基础知识

    上一篇介绍了五种NIO模型,本篇将介绍Java中的NIO类库,为学习netty做好铺垫 Java NIO 由3个核心组成,分别是Channels,Buffers,Selectors.本文主要介绍着三个 ...

  5. 关于Java中面向对象章节、IO 流中的重点基础知识。

    一.面向对象的三大特征,以及作用. 答:面向对象的三大特征即,封装性.继承性.多态性. 其分别的作用为 : 封装作用:将数据封装起来,提高数据的安全性, 继承作用:提高代码的复用性,减少冗余代码. 多 ...

  6. 再谈一次关于Java中的 AIO(异步IO) 与 NIO(非阻塞IO)

    今天用ab进行压力测试时,无意发现的: Requests per second:    xxx [#/sec] (mean) ab -n 5000 -c 1000 http://www:8080/up ...

  7. JAVA中的NIO(二)

    一.内存文件映射 内存文件映射允许我们创建和修改那些因为太大而不能放入内存中的文件.有了内存文件映射,我们就可以假定整个文件都在内存中,而且可以完全把文件当作数组来访问. package com.dy ...

  8. JAVA中的NIO(一)

    1.IO与NIO IO就是普通的IO,或者说原生的IO.特点:阻塞式.内部无缓冲,面向流. NIO就是NEW IO,比原生的IO要高效.特点:非阻塞.内部有缓存,面向缓冲. 要实现高效的IO操作,尤其 ...

  9. JAVA 中BIO,NIO,AIO的理解

    [转自]http://qindongliang.iteye.com/blog/2018539 ?????????????????????在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解 ...

随机推荐

  1. EL十一大内置对象

    这是一个内置对象可以直接拿来使用,不需要再去声明. 1.读取页面上下文: (1)pageContext对象: 获取URL和URI: <body> URI:${pageContext.req ...

  2. css实现斜角效果

    重点代码: 使用一张图片盖住div,实现斜角效果 .triangle { position: absolute; top:; left:; width: 36px; height: 36px; bac ...

  3. robotframework框架 - seleniumLibrary 关键字解读-全攻略

    在robotframework当中,要实现web自动化,则需要使用SeleniumLibrary这个库. 目前版本中,有180+关键字.随着版本的更新,关键字的个数和名字也会有所变动. 在网上没有找到 ...

  4. [go设计模式]简单工厂模式

    优点 工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可 ...

  5. win10家庭版升级专业版

    在网上随便百度一个产品密钥,记得一定要先断网(这个很重要),否则很难升级. 升级之后发现产品未激活,下载KMS激活一下就可以了.

  6. Node.js入门教程 第四篇 (流及文件操作)

    流 Stream是Node.js中的抽象接口,有不少Node.js对象实现自Stream. 所有的Stream对象都是EventEmitter 的实例. 例如:fs模块(用于读写操作文件的模块) fs ...

  7. 02-14 scikit-learn库之逻辑回归

    目录 scikit-learn库之逻辑回归 一.LogisticRegression 1.1 使用场景 1.2 代码 1.3 参数详解 1.4 属性 1.5 方法 二.LogisticRegressi ...

  8. 一篇文章教会你jQuery应用

    一 认识jQuery jQuery是JavaScript Query的缩写形式.jQuery是一款非常优秀的JavaScript库,即便是MVVM框架盛行的今天,也有超过半数的网页及应用直接或间接的使 ...

  9. python编程基础之三十一

    面向对象:一开始接触面向对象其实感觉不好用,但是对于一些复杂的问题,使用面向对象其实更加容易,逻辑不容易混乱 它的核心是:类 和 对象 类:对一系列事物的抽象概念,可以视为一张图纸, 对象:就是对类这 ...

  10. Jackson中@JsonProperty等常用注解

    Java生态圈中有很多处理JSON和XML格式化的类库,Jackson是其中比较著名的一个.虽然JDK自带了XML处理类库,但是相对来说比较低级 本文将介绍的Jackson常用注解:精简概述 Jack ...