1, 同步 VS. 异步
比较的是当某种事件发生时调用处理函数的方式,
同步:应用程序主动调用处理函数,
异步:操作系统调用应用程序的处理函数(也叫回调函数),对应用程序而言是被动过程。
2, 阻塞 VS. 非阻塞
阻塞:应用程序发起IO请求,IO请求(假设是网络上的IO)会经过网络、网卡、操作系统等,在这个过程中应用程序必须等到操作系统完成IO操作,才能继续后面的事情,因此称为阻塞,
非阻塞:应用程序在发起IO请求后不必等待操作系统完成IO操作,应用程序可以继续做后面的事情,应用程序可以主动查询(轮训)某种IO事件是否完成,并调用相应的处理函数,或者在IO事件发生时操作系统调用应用程序的回调函数。
3, BIO,NIO,AIO
JDK版本 | 同步and 阻塞 | 模型类型 | 隐喻 | |
BIO | 1.0 | 同步阻塞 | 一连接一线程 | 一个人开了一个餐厅,需要负责迎客(Accept connection)、 等待客户点菜(Read data)、炒菜(处理请求)、 等待客户用餐(Write data)、收银(Close connection),此人在任何时刻 只能服务于一个客户,新来的客户必须等待。 改进型:一人迎客,之后再交由店里空闲的员工独自完成点菜、炒菜、 等待客户用餐、收银等操作,即多线程模式,这在一定程度上能提高性能。 |
NIO | 1.4 | 同步非阻塞 | 一请求一线程,Reactor | 一个人开了一个餐厅,负责迎客等所有操作,迎客后让客户点菜,在客户点菜的过程中可以 做其它的操作,并每隔一段时间查看客户是否点菜完毕,如果点菜完毕则开始 炒菜。其它操作类似,如客户用餐,不用等待客户用餐,只需每隔一段时间查看 客户是否用餐完毕,再进行后续操作。 改进型:一个人负责检查是否有某种事件发生,如是否有新客户到来,是否有某个客户点菜 完毕,是否有某个客户用餐完毕等等,多个员工负责处理事件,如某个客户点菜完毕 则让一个空闲的员工来炒菜,如果某个客户用餐完毕,则让一个空闲的员工来收银等等。 由于不用等待客户(即没有IO阻塞),在很大程度上提高了系统系能。 |
AIO | 1.7 | 异步非阻塞 | 一有效请求一线程,Proactor, 需要OS支持,Windows:IOCP,Linux:epoll
| 与NIO类似,只是不用主动查询是否有某种事件发生,而是被告知该事件已发生。如客户 点菜完毕后会主动说“我已经点菜完毕了”,然后让一个空闲的员工来取菜单并炒菜。 AIO是真正意义的异步IO,需要OS支持,在读IO数据时操作系统会将数据读入到应用程序 指定的缓存(ByteByffer)中,应用程序直接使用即可,不像NIO还要应用程序自己读取。 AIO能简化应用程序的编写,因为其只关心有效的请求,将指定的请求绑定到对应的回调函数 中即可,OS会自动调用回调函来处理请求。 |
4, BIO代码片段
package com.my.study.io.bio;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
private static final int PORT = 8888;
private ServerSocket serverSocket = null;
private ExecutorService service = Executors.newFixedThreadPool(5);
private void startServer() {
try {
serverSocket = new ServerSocket(PORT);
System.out.println("Server started on port: " + PORT);
while (true) {
Socket socket = serverSocket.accept();
System.out.println("Received a new connection.");
service.submit(new RequestResolver(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class RequestResolver implements Runnable {
private Socket socket;
public RequestResolver(Socket socket) {
this.socket = socket;
}
public void run() {
DataInputStream din = null;
DataOutputStream dout = null;
try {
long threadId = Thread.currentThread().getId();
InputStream in = socket.getInputStream();
din = new DataInputStream(in);
String str = din.readUTF();
System.out.println("Thread: " + threadId + ", read message: "
+ str);
OutputStream out = socket.getOutputStream();
dout = new DataOutputStream(out);
dout.writeUTF("Response from server.");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (din != null) {
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dout != null) {
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (!socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
new Server().startServer();
}
}
package com.my.study.io.bio;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
private static final int PORT = 8888;
private static void testSendMessage() {
Socket socket = null;
DataInputStream din = null;
DataOutputStream dout = null;
try {
socket = new Socket("127.0.0.1", PORT);
OutputStream out = socket.getOutputStream();
dout = new DataOutputStream(out);
dout.writeUTF("This message is from a client.");
InputStream in = socket.getInputStream();
din = new DataInputStream(in);
String str = din.readUTF();
System.out.println("Response from server: " + str);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (din != null) {
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dout != null) {
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (!socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
testSendMessage();
}
}
5,NIO代码片段
<pre class="java" name="code">package com.my.study.io.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Server {
private static final int PORT = 8888;
private Selector selector;
private void startServer() {
try {
selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel
.open();
serverSocketChannel.configureBlocking(false);
SocketAddress address = new InetSocketAddress(PORT);
serverSocketChannel.bind(address);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started on port: " + PORT);
while (true) {
int selectCode = selector.select(1000);
if (selectCode == 0) {
continue;
}
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
System.out.println("Received a request.");
serverSocketChannel = (ServerSocketChannel) key
.channel();
SocketChannel socketChannel = serverSocketChannel
.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
readData(key);
} else {
System.out.println("Key is no recognised, key: " + key);
}
it.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void readData(SelectionKey key) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
try {
socketChannel.read(buffer);
byte[] bytes = buffer.array();
String message = new String(bytes).toString();
System.out.println("Received message from client: " + message);
socketChannel.write(ByteBuffer.wrap("Response from server."
.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server().startServer();
}
}
package com.my.study.io.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class Client {
private Selector selector;
public void initClient(String ip, int port) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
this.selector = Selector.open();
channel.connect(new InetSocketAddress(ip, port));
channel.register(selector, SelectionKey.OP_CONNECT);
}
public void listen() throws IOException {
while (true) {
int selectCode = selector.select(1000);
if (selectCode == 0) {
continue;
}
Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if (key.isConnectable()) {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(this.selector, SelectionKey.OP_READ);
channel.write(ByteBuffer.wrap(new String(
"Message from a client.").getBytes()));
} else if (key.isReadable()) {
readData(key);
}
it.remove();
}
}
}
public void readData(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("Response from server: " + msg);
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.initClient("localhost", 8888);
client.listen();
}
}
6,AIO代码片段
<pre class="java" name="code">package com.my.study.io.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;
public class Server {
private static final int PORT = 8888;
private AsynchronousServerSocketChannel server;
private void startServer() {
try {
server = AsynchronousServerSocketChannel.open().bind(
new InetSocketAddress(PORT));
System.out.println("Server started on port: " + PORT);
server.accept(null,
new CompletionHandler<AsynchronousSocketChannel, Object>() {
final ByteBuffer buffer = ByteBuffer
.allocate(1024 * 1024);
public void completed(AsynchronousSocketChannel result,
Object attachment) {
buffer.clear();
try {
result.read(buffer).get(100, TimeUnit.SECONDS);
buffer.flip();
String str = new String(buffer.array());
System.out.println("Received message: " + str);
result.write(ByteBuffer
.wrap("Response from server."
.getBytes()));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
result.close();
server.accept(null, this);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void failed(Throwable exc, Object attachment) {
System.out.println("Failed: " + exc);
}
});
while (true) {
System.out.println("Server main thread.");
try {
Thread.sleep(1000 * 60 * 60 * 24 * 365 * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server().startServer();
}
}
package com.my.study.io.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class Client {
private AsynchronousSocketChannel client;
private void start() {
try {
client = AsynchronousSocketChannel.open();
} catch (IOException e) {
e.printStackTrace();
return;
}
client.connect(new InetSocketAddress("127.0.0.1", 8888), null,
new CompletionHandler<Void, Object>() {
public void completed(Void result, Object attachment) {
client.write(ByteBuffer
.wrap("Request message from client.".getBytes()));
}
public void failed(Throwable exc, Object attachment) {
System.out.println("Connect Failed: " + exc);
}
});
final ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
client.read(buffer, null, new CompletionHandler<Integer, Object>() {
public void completed(Integer result, Object attachment) {
String str = new String(buffer.array());
System.out.println("Response from server: " + str);
}
public void failed(Throwable exc, Object attachment) {
System.out.println("Read Failed: " + exc);
}
});
while (true) {
System.out.println("Client main thread.");
try {
Thread.sleep(1000 * 60 * 60 * 24 * 365 * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Client().start();
}
}