同步阻塞、同步非阻塞、异步非阻塞的代码层面理解
2018-11-07 本文已影响0人
sunshujie1990
- Java传统io是同步阻塞io
- serverSocket.accept()的时候会阻塞
- br.readLine()的时候会阻塞
- 代码串行执行,没有多线程和回调,是同步进行的。
ServerSocket serverSocket = new ServerSocket(8080);
Socket accept = serverSocket.accept();// 1
InputStream inputStream = accept.getInputStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(inputStream));
String s = br.readLine();// 2
System.out.println(s);
- Java nio一般称为同步非阻塞。
- channel.configureBlocking(false);设置的非阻塞是接受连接、读写数据不阻塞了,但是selector.select()的时候是阻塞的。
- 把多路复用理解透彻也就不再纠结是同步阻塞还是同步非阻塞或者是异步非阻塞了,因为解决性能瓶颈不在于这些概念, 而在于如何节约系统资源。
- 传统io的瓶颈在并发,并发大的时候需要大量线程处理,而多路复用可以用单线程或者少量线程处理多channel的链接、读写就绪等事件,节约了系统资源,从而提高了并发性能。
ServerSocketChannel channel = ServerSocketChannel.open();
// 通过channel的配置可以配置为非阻塞
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 虽然是非阻塞,也有阻塞的地方,在selector.select()的时候, 如果没有事件发生,会阻塞在这里。
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
// selector.select()已经阻塞了,这里客户端链接已经准备好了,所以会马上创建好tcp连接,这里是非阻塞的
SocketChannel client = channel.accept();
if (client == null) {
continue;
}
client.configureBlocking(false);
client.write(ByteBuffer.wrap("hello world".getBytes()));
// 给同一个selector注册客户端channel的read事件,因为一个selector能够注册多个channel,并且能够监听这些channel的accept,read,write等事件,所以叫做多路复用。
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel curClient = (SocketChannel) key.channel();
ByteBuffer bf = ByteBuffer.allocate(512);
// selector.select()的时候表明已经有数据过来了,所以这里是非阻塞
curClient.read(bf);
String s = new String(bf.array(), "UTF-8");
System.out.println(s);
}
}
}