一、认识同步与异步
1、同步,异步是指应用程序和内核的相互交互而言的
同步:是指用户进程触发io操作等待或者轮训的方式查看io操作是否就绪
异步:异步调用发出调用之后,不会立刻得到结果,而是通过被调用者通知调用者,或者回调函数处理调用。
二、阻塞和非阻塞
阻塞和非阻塞是针对于进程访问数据的时候,根据IO状态采取不同方式
阻塞:读写操作一直等待,
非阻塞:读写会返回一个状态值,进行下一步
例:
洗衣服逻辑:
1、洗衣服,一直在旁边等着洗衣机洗衣服,然后晾干——同步阻塞
2、洗衣服,洗衣机在洗衣服,自己去做饭,时不时看一下衣服洗好了没有——同步非阻塞
3、洗衣服,一直在旁边等着洗衣机洗衣服,然后晾干——异步阻塞
4、洗衣服,洗衣机在洗衣服,自己去做饭,衣服洗好了没有——异步非阻塞
三、BIO的了解
同步阻塞IO,服务器实现模式为一个连接一个线程。
即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
例: 服务端:
public class IOServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress("127.0.0.1",8081)); while (true){ Socket socket = serverSocket.accept(); new Thread(()->{ try { byte[] bytes = new byte[1024]; int len = socket.getInputStream().read(bytes); System.out.println(new String(bytes,0,len)); socket.getOutputStream().write(bytes,0,len); socket.getOutputStream().flush(); } catch (IOException e) { e.printStackTrace(); } }).start(); }
客户端:
public class IOClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",8081); socket.getOutputStream().write("hello".getBytes()); socket.getOutputStream().flush(); System.out.println("server send back data ====="); byte[] bytes = new byte[1024]; int len = socket.getInputStream().read(bytes); System.out.println(new String(bytes,0,len)); socket.close(); } }
四、NIO的了解
同步非阻塞IO (non-blocking IO / new io)是指JDK 1.4 及以上版本
服务器实现模式为一个请求一个通道。
即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。
通道(Channels):NIO 新引入的最重要的抽象是通道的概念。Channel 数据连接的通道。数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中 。
缓冲区(Buffers):通道channel可以向缓冲区Buffer中写数据,也可以像buffer中存数据。
选择器(Selector):使用选择器,借助单一线程,就可对数量庞大的活动 I/O 通道实时监控和维护。
当一个连接创建后,不会需要对应一个线程,这个连接会被注册到多路复用器,所以一个连接只需要一个线程即可,所有的连接需要一个线程就可以操作,该线程的多路复用器会轮训,发现连接有请求时,才开启一个线程处理。
NIO模型中selector的作用,一条连接来了之后,现在不创建一个while死循环去监听是否有数据可读了,而是直接把这条连接注册到selector上,然后通过检查这个selector,就可以批量监测出有数据可读的连接,进而读取数据。
例:客户端
public class NIOClient { public static void main(String[] args) { InetSocketAddress address = new InetSocketAddress("127.0.0.1",8888); SocketChannel channel = null; ByteBuffer buffer = ByteBuffer.allocate(1024); try { channel = SocketChannel.open(); channel.connect(address); Scanner sc = new Scanner(System.in); while (true){ System.out.println("客户端即将给 服务器发送数据.."); String line = sc.nextLine(); if(line.equals("exit")){ break; } buffer.put(line.getBytes("UTF-8")); buffer.flip(); channel.write(buffer); buffer.clear(); int readLen = channel.read(buffer); if(readLen == -1){ break; } buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); System.out.println("收到了服务器发送的数据 : "+ new String(bytes,"UTF-8")); buffer.clear(); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != channel){ try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
五、AIO的了解
异步非阻塞IO。A代表asynchronize。
当有流可以读时,操作系统会将可以读的流传入read方法的缓冲区,并通知应用程序,对于写操作,OS将write方法的流写入完毕是操作系统会主动通知应用程序。因此read和write都是异步 的,完成后会调用回调函数。
使用场景:连接数目多且连接比较长(重操作)的架构,比如相册服务器。重点调用了OS参与并发操作,编程比较复杂。Java7开始支持。
原文:https://www.cnblogs.com/lqh969696/p/14656717.html