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