Java NIO道理圖文剖析及代碼完成。本站提示廣大學習愛好者:(Java NIO道理圖文剖析及代碼完成)文章只能為提供參考,不一定能成為您想要的結果。以下是Java NIO道理圖文剖析及代碼完成正文
媒介:
比來在剖析hadoop的RPC(Remote Procedure Call Protocol ,長途進程挪用協定,它是一種經由過程收集從長途盤算機法式上要求辦事,而不須要懂得底層收集技巧的協定。可以參考:http://baike.百度.com/view/32726.htm )機制時,發明hadoop的RPC機制的完成重要用到了兩個技巧:靜態署理(靜態署理可以參考博客:http://weixiaolu.iteye.com/blog/1477774 )和java NIO。為了可以或許准確地剖析hadoop的RPC源碼,我認為很有需要先研討一下java NIO的道理和詳細完成。
這篇博客我重要從兩個偏向來剖析java NIO
目次:
一.java NIO 和壅塞I/O的差別
1. 壅塞I/O通訊模子
2. java NIO道理及通訊模子
二.java NIO辦事端和客戶端代碼完成
詳細剖析:
一.java NIO 和壅塞I/O的差別
1. 壅塞I/O通訊模子
假設如今你對壅塞I/O已有了必定懂得,我們曉得壅塞I/O在挪用InputStream.read()辦法時是壅塞的,它會一向比及數據到來時(或超時)才會前往;異樣,在挪用ServerSocket.accept()辦法時,也會一向壅塞到有客戶端銜接才會前往,每一個客戶端銜接過去後,辦事端都邑啟動一個線程行止理該客戶真個要求。壅塞I/O的通訊模子表示圖以下:
假如你細細剖析,必定會發明壅塞I/O存在一些缺陷。依據壅塞I/O通訊模子,我總結了它的兩點缺陷:
1. 當客戶端多時,會創立年夜量的處置線程。且每一個線程都要占用棧空間和一些CPU時光
2. 壅塞能夠帶來頻仍的高低文切換,且年夜部門高低文切換能夠是有意義的。
在這類情形下非壅塞式I/O就有了它的運用遠景。
2. java NIO道理及通訊模子
Java NIO是在jdk1.4開端應用的,它既可以說成“新I/O”,也能夠說成非壅塞式I/O。上面是java NIO的任務道理:
1. 由一個專門的線程來處置一切的 IO 事宜,並擔任分發。
2. 事宜驅念頭制:事宜到的時刻觸發,而不是同步的去監督事宜。
3. 線程通信:線程之間經由過程 wait,notify 等方法通信。包管每次高低文切換都是成心義的。削減無謂的線程切換。
浏覽過一些材料以後,上面貼出我懂得的java NIO的任務道理圖:
(注:每一個線程的處置流程年夜概都是讀取數據、解碼、盤算處置、編碼、發送呼應。)
Java NIO的辦事端只需啟動一個專門的線程來處置一切的 IO 事宜,這類通訊模子是怎樣完成的呢?呵呵,我們一路來探討它的奧妙吧。java NIO采取了雙向通道(channel)停止數據傳輸,而不是單向的流(stream),在通道上可以注冊我們感興致的事宜。一共有以下四種事宜:
事宜名
對應值
辦事端吸收客戶端銜接事宜
SelectionKey.OP_ACCEPT(16)
客戶端銜接辦事端事宜
SelectionKey.OP_CONNECT(8)
讀事宜
SelectionKey.OP_READ(1)
寫事宜
SelectionKey.OP_WRITE(4)
辦事端和客戶端各自保護一個治理通道的對象,我們稱之為selector,該對象能檢測一個或多個通道 (channel) 上的事宜。我們以辦事端為例,假如辦事真個selector上注冊了讀事宜,某時辰客戶端給辦事端發送了一些數據,壅塞I/O這時候會挪用read()辦法壅塞地讀取數據,而NIO的辦事端會在selector中添加一個讀事宜。辦事真個處置線程會輪詢地拜訪selector,假如拜訪selector時發明有感興致的事宜達到,則處置這些事宜,假如沒有感興致的事宜達到,則處置線程會一向壅塞直到感興致的事宜達到為止。上面是我懂得的java NIO的通訊模子表示圖:
二.java NIO辦事端和客戶端代碼完成
為了更好地輿解java NIO,上面貼出辦事端和客戶真個簡略代碼完成。
辦事端:
package cn.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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* NIO辦事端
* @author 巷子
*/
public class NIOServer {
//通道治理器
private Selector selector;
/**
* 取得一個ServerSocket通道,並對該通道做一些初始化的任務
* @param port 綁定的端標語
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 取得一個ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 設置通道為非壅塞
serverChannel.configureBlocking(false);
// 將該通道對應的ServerSocket綁定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 取得一個通道治理器
this.selector = Selector.open();
//將通道治理器和該通道綁定,並為該通道注冊SelectionKey.OP_ACCEPT事宜,注冊該事宜後,
//當該事宜達到時,selector.select()會前往,假如該事宜沒達到selector.select()會一向壅塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
/**
* 采取輪詢的方法監聽selector上能否有須要處置的事宜,假如有,則停止處置
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
System.out.println("辦事端啟動勝利!");
// 輪詢拜訪selector
while (true) {
//當注冊的事宜達到時,辦法前往;不然,該辦法會一向壅塞
selector.select();
// 取得selector當選中的項的迭代器,選中的項為注冊的事宜
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 刪除已選的key,以防反復處置
ite.remove();
// 客戶端要求銜接事宜
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key
.channel();
// 取得和客戶端銜接的通道
SocketChannel channel = server.accept();
// 設置成非壅塞
channel.configureBlocking(false);
//在這裡可以給客戶端發送信息哦
channel.write(ByteBuffer.wrap(new String("向客戶端發送了一條信息").getBytes()));
//在和客戶端銜接勝利以後,為了可以吸收到客戶真個信息,須要給通道設置讀的權限。
channel.register(this.selector, SelectionKey.OP_READ);
// 取得了可讀的事宜
} else if (key.isReadable()) {
read(key);
}
}
}
}
/**
* 處置讀取客戶端發來的信息 的事宜
* @param key
* @throws IOException
*/
public void read(SelectionKey key) throws IOException{
// 辦事器可讀撤消息:獲得事宜產生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
// 創立讀取的緩沖區
ByteBuffer buffer = ByteBuffer.allocate(10);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("辦事端收到信息:"+msg);
ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
channel.write(outBuffer);// 將新聞回送給客戶端
}
/**
* 啟動辦事端測試
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.initServer(8000);
server.listen();
}
}
客戶端:
package cn.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;
/**
* NIO客戶端
* @author 巷子
*/
public class NIOClient {
//通道治理器
private Selector selector;
/**
* 取得一個Socket通道,並對該通道做一些初始化的任務
* @param ip 銜接的辦事器的ip
* @param port 銜接的辦事器的端標語
* @throws IOException
*/
public void initClient(String ip,int port) throws IOException {
// 取得一個Socket通道
SocketChannel channel = SocketChannel.open();
// 設置通道為非壅塞
channel.configureBlocking(false);
// 取得一個通道治理器
this.selector = Selector.open();
// 客戶端銜接辦事器,其實辦法履行並沒有完成銜接,須要在listen()辦法中調
//用channel.finishConnect();能力完成銜接
channel.connect(new InetSocketAddress(ip,port));
//將通道治理器和該通道綁定,並為該通道注冊SelectionKey.OP_CONNECT事宜。
channel.register(selector, SelectionKey.OP_CONNECT);
}
/**
* 采取輪詢的方法監聽selector上能否有須要處置的事宜,假如有,則停止處置
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
// 輪詢拜訪selector
while (true) {
selector.select();
// 取得selector當選中的項的迭代器
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 刪除已選的key,以防反復處置
ite.remove();
// 銜接事宜產生
if (key.isConnectable()) {
SocketChannel channel = (SocketChannel) key
.channel();
// 假如正在銜接,則完成銜接
if(channel.isConnectionPending()){
channel.finishConnect();
}
// 設置成非壅塞
channel.configureBlocking(false);
//在這裡可以給辦事端發送信息哦
channel.write(ByteBuffer.wrap(new String("向辦事端發送了一條信息").getBytes()));
//在和辦事端銜接勝利以後,為了可以吸收到辦事真個信息,須要給通道設置讀的權限。
channel.register(this.selector, SelectionKey.OP_READ);
// 取得了可讀的事宜
} else if (key.isReadable()) {
read(key);
}
}
}
}
/**
* 處置讀取辦事端發來的信息 的事宜
* @param key
* @throws IOException
*/
public void read(SelectionKey key) throws IOException{
//和辦事真個read辦法一樣
}
/**
* 啟動客戶端測試
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOClient client = new NIOClient();
client.initClient("localhost",8000);
client.listen();
}
}
小結:
終究把靜態署理和java NIO剖析完了,呵呵,上面就要剖析hadoop的RPC機制源碼了,博客地址:http://weixiaolu.iteye.com/blog/1504898 。不外假如對java NIO的懂得存在貳言的,迎接一路評論辯論。
如需轉載,請注明出處:http://weixiaolu.iteye.com/blog/1479656