1. Java Classic(Blocking) I/O
1.1 Streams 字节流
继承Output/InputStream抽象类的几种I/O
- 包括ByteArrayOutputStream,字节流,字节数组
- FileOutputStream,字节流,更适用于图片等二进制文件
- FilterOutputStream是一个超类,通过装饰者模式为上述基本的Stream类型添加额外功能,
- 包括,Buffered,增加字节流的缓存能力,提升I/O效率与性能
- Data,针对Java原生数据类型的
- PrintStream,常用日志,无I/O Exception(只存在Output)
- ObjectOutputStream Java自带的序列化反序列化
- PipedOutputStream 管道
1.2 Writer 和 Reader字符流
一个字节是8bit,一个字符是16bit,且字节流不知道字符集和字符编码,所以需要字符流,都继承自Writer/Reader
- BufferedWriter,类似BufferedOutputStream,通过缓冲区处理,提高I/O性能,装饰者模式
- CharArrayWriter,类似ByteArrayStream,只不过字节变成了字符
- InputStreamReader/OutputStreamWriter,字节转字符输入,字符转字节输出
- FileWriter,字符流读写文件
- StringWriter,String的装饰者,添加Writer和Reader操作
- PipedWriter管道读写
- PrintWriter,类似PrintStream,多了格式化输出字符串
1.3 Java Blocking I/O 网络通信实现
数据按照有限大小的数据报(datagram)进行传输,每个数据报由两部分,首部header和负载payload
首部包含数据报目的地址和端口,来源地址和端口,校验和保证可靠性的信息。数据报大小有限,需要分解多个包,有丢失或者损坏,重传。乱序等情况
Java Socket已封装并解决了这些网络底层细节问题
Socket是一个全双工通道,ServerSocket的accpt()会一直阻塞知道某个请求建立连接,返回连接的socket对象
一个简单的RPC实现来说明
ConsumerProxy消费者代理
package framework;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
/*
* 服务消费代理接口
* Service API的代理类
* 与服务提供方通信参数和返回结果,使通信过程透明
* */
public class ConsumerPoxy {
public static <T> T consume (final Class<T> interfaceClass,final String host,final int port) throws Exception {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket=new Socket(host,port);//新建立socket
try {
ObjectOutputStream outputStream=new ObjectOutputStream(socket.getOutputStream());
try {
outputStream.writeUTF(method.getName());
outputStream.writeObject(args);
ObjectInputStream inputStream=new ObjectInputStream(socket.getInputStream());
try {
Object result=inputStream.readObject();
if (result instanceof Throwable){
throw (Throwable) result;
}
return result;
} finally {
inputStream.close();
}
} finally {
outputStream.close();
}
} finally {
socket.close();//关闭socket
}
}
}
);
}
}
ProviderReflect 提供者反射
package framework;
import org.apache.commons.lang3.reflect.MethodUtils;
import sun.reflect.misc.MethodUtil;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
* 服务提供方
* 通过Socket接收Consumer的参数,通过Socket返回结果
*
* */
public class ProviderReflect {
private static final ExecutorService executorService = Executors.newCachedThreadPool();
public static void provider(final Object service, final int port) throws Exception {
final ServerSocket serverSocket = new ServerSocket(port);
while (true) {
final Socket socket = serverSocket.accept(); //阻塞
executorService.execute(new Runnable() {
public void run() {
try {
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
try {
String name = inputStream.readUTF();
Object[] args = (Object[]) inputStream.readObject();
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
try {
Object result = MethodUtils.invokeExactMethod(service, name, args);
outputStream.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
outputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
}
2. Java Non-blocking I/O (NIO)
2.1 Buffer缓冲区
Classic I/O面向Stream,NIO面向Buffer对象,效率更高。
Buffer是java.nio中的抽象类,基于它实现了一系列基本Buffer子类,如ByteBuffer,CharBuffer
所有Buffer都有如下几本属性:0<=mark<=position<=limit<=capacity
- 容量Capacity:缓冲区能容下的最大数量,创建时被设定,永远不能修改
- 上界Limit:缓冲区的现存元素计数
- 位置Position:下一个要读写的元素,由get(),put()函数更新
- 标记Mark:mark()->mark=position,reset->postition=mark。在mark()之前时undefined
Buffer
/**
* Flips this buffer. The limit is set to the current position and then
* the position is set to zero. If the mark is defined then it is
* discarded.
*
* <p> After a sequence of channel-read or <i>put</i> operations, invoke
* this method to prepare for a sequence of channel-write or relative
* <i>get</i> operations. For example:
*
* <blockquote><pre>
* buf.put(magic); // Prepend header
* in.read(buf); // Read data into rest of buffer
* buf.flip(); // Flip buffer
* out.write(buf); // Write header + data to channel</pre></blockquote>
*
* <p> This method is often used in conjunction with the {@link
* java.nio.ByteBuffer#compact compact} method when transferring data from
* one place to another. </p>
*
* @return This buffer
*/
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
/**
* Rewinds this buffer. The position is set to zero and the mark is
* discarded.
*
* <p> Invoke this method before a sequence of channel-write or <i>get</i>
* operations, assuming that the limit has already been set
* appropriately. For example:
*
* <blockquote><pre>
* out.write(buf); // Write remaining data
* buf.rewind(); // Rewind buffer
* buf.get(array); // Copy data into array</pre></blockquote>
*
* @return This buffer
*/
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
2.2 Channel通道
Channel是一个全双工通道,不同于Classic IO的Stream。如果说Buffer时运载数据的卡车,那么channel就是卡车行驶的道路。传输对象只能为Buffer。通道主要由接口指定,不同操作系统上通道差别很大。
2.3 selector选择器
Channel在Selector上注册,Selector不断轮询注册在其上的Channel,能够感知到Channel的可读可写的事件。用较少线程维护大量网络连接,减少线程之间的切换开销。在linux下JDK使用epoll()系统调用代替了传统的select实现,使其没有最大的连接句柄限制。
3. NIO2,Asynchronous I/O 介绍
NIO2在File操作方面进行了升级,对文件操作有较高需求的可以看一下。
Asynchronous I/O 是NIO2中的异步I/O组件
AsynchronousFileChannel提供异步读写文件的功能。
AsynchronousSocketChannel与AsynchronousServerSocketChannel实现了异步I/O网络模型,通过实现CompletionHandler < T,T >的接口通过Channel read和write buffer