java NIO

nio是new io的簡稱,從jdk1.4就被引入了。現在的jdk已經到了1.6了,可以說不是什麼新東西了。但其中的一些思想值得我來研究。這兩天,我研究了下其中的套接字部分,有一些心得,在此分享。 首先先分析下:爲什麼要nio套接字? nio的主要作用就是用來解決速度差異的。舉個例子:計算機處理的速度,和用戶按鍵盤的速度。這兩者的速度相差懸殊。如果按照經典的方法:一個用戶設定一個線程,專門等待用戶的輸入,無形中就造成了嚴重的資源浪費:每一個線程都需要珍貴的cpu時間片,由於速度差異造成了在這個交互線程中的cpu都用來等待。 nio套接字是怎麼做到的? 其實,其中的思想很簡單:輪詢。一個線程輪詢多個input;傳統的方式是:有n個客戶端就要有n個服務線程+一個監聽線程,現在採取這種凡是,可以僅僅使用1個線程來代替n個服務線程以此來解決。 具體應用例子: 在ftp的控制連接中,因爲只有少量的字符命令進行傳輸,所以可以考慮利用這種輪詢的方式實現,以節省資源。 具體見例子。 Java代碼
  package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }
  public IoEchoServer() throws IOException {
  ServerSocket server = new ServerSocket(1984);
  while (true) {
  Socket socket = server.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  System.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  }

 

 

 package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }
  public IoEchoServer() throws IOException {
  ServerSocket <A title=server href="http://www.google.cn/search?sbi=server&q=server&sbb=搜索&sa=搜索&client=pub-6430022987645146&forid=1&prog=aff&ie=GB2312&oe=GB2312&hl=zh-CN" target=_blank>server</A> = new ServerSocket(1984);
  while (true) {
  Socket socket = <A title=server href="http://www.google.cn/search?sbi=server&q=server&sbb=搜索&sa=搜索&client=pub-6430022987645146&forid=1&prog=aff&ie=GB2312&oe=GB2312&hl=zh-CN" target=_blank>server</A>.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  <A title=system href="http://www.alimama.com/membersvc/buyadzone/buy_ad_zone.htm?adzoneid=892989 " target=_blank>system</A>.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  }
  package com.cxz.io;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Collections;
  public class IoEchoServer implements Runnable {
  // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();
  Map<String, Socket> socketMap = Collections
  .synchronizedMap(new HashMap<String, Socket>());
  int threadCounter = 0;
  synchronized private int getCounter() {
  return threadCounter++;
  }

 

public IoEchoServer() throws IOException {
  ServerSocket server = new ServerSocket(1984);
  while (true) {
  Socket socket = server.accept();
  // happened in the main thread.
  // localSocket.set(socket);
  String threadName = "---Thread" + getCounter() + "---";
  socketMap.put(threadName, socket);
  this.start(threadName);
  }
  }
  /**
  * @param args
  * @throws IOException
  */
  public static void main(String[] args) throws IOException {
  new IoEchoServer();
  }
  public void run() {
  try {
  Socket socket = socketMap.get(Thread.currentThread().getName());
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //PrintWriter out = new PrintWriter(socket.getOutputStream());
  String buffer = null;
  while(!"END".equals(buffer)){
  buffer = in.readLine();
  system.out.println(buffer);
  }
  in.close();
  socket.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  public void start(String threadName) {
  new Thread(this, threadName).start();
  }
  } 下面這個例子採取了nio方式實現,雖然還是有阻塞部分,但是與上一個相比,效率已經大幅提高。僅僅阻塞到一個監聽線程中。 Java代碼
  package com.cxz.nio;
  import java.io.IOException;
  import java.net.InetSocketAddress;
  import java.nio.ByteBuffer;
  import java.nio.CharBuffer;
  import java.nio.channels.SelectionKey;
  import java.nio.channels.Selector;
  import java.nio.channels.ServerSocketChannel;
  import java.nio.channels.SocketChannel;
  import java.nio.charset.Charset;
  import java.nio.charset.CharsetDecoder;
  import java.util.Iterator;
  import java.util.Set;
  public class NioEchoServer {
  private static Selector roller = null;
  private static final int port = 8080;
  private static NioEchoServer instance = null;
  private ThreadLocal<StringBuffer> stringLocal = new ThreadLocal<StringBuffer>();
  private NioEchoServer() throws IOException {
  ServerSocketChannel serverChannel = ServerSocketChannel.open();
  serverChannel.socket().bind(new InetSocketAddress(port));
  serverChannel.configureBlocking(false);
  serverChannel.register(roller, SelectionKey.OP_ACCEPT);
  }
  public synchronized static NioEchoServer getInstance() throws IOException {
  if (instance == null) {
  roller = Selector.open();
  instance = new NioEchoServer();
  }
  return instance;
  }
  public void start() throws IOException {
  int keyAdded = 0;
  while ((keyAdded = roller.select()) > 0) {
  Set<SelectionKey> keySets = roller.selectedKeys();
  Iterator iter = keySets.iterator();
  while (iter.hasNext()) {
  SelectionKey key = (SelectionKey) iter.next();
  iter.remove();
  actionHandler(key);
  }
  }
  }

 

public void actionHandler(SelectionKey key) throws IOException {
  if (key.isAcceptable()) {
  ServerSocketChannel serverChannel = (ServerSocketChannel) key
  .channel();
  SocketChannel socketChannel = serverChannel.accept();
  socketChannel.configureBlocking(false);
  socketChannel.register(roller, SelectionKey.OP_READ);
  } else if (key.isReadable()) {
  ByteBuffer buffer = ByteBuffer.allocate(16);
  SocketChannel socketChannel = (SocketChannel) key.channel();
  socketChannel.read(buffer);
  buffer.flip();
  String temp = decode(buffer);
  StringBuffer strBuffer = stringLocal.get();
  if (strBuffer == null) {
  strBuffer = new StringBuffer();
  }
  strBuffer.append(temp);
  if (temp.equals("/r/n")) {
  System.out.println(strBuffer.toString());
  strBuffer = null;
  }
  stringLocal.set(strBuffer);
  }
  }
  public String decode(ByteBuffer buffer) {
  Charset charset = null;
  CharsetDecoder decoder = null;
  CharBuffer charBuffer = null;
  try {
  charset = Charset.forName("UTF-8");
  decoder = charset.newDecoder();
  charBuffer = decoder.decode(buffer);
  return charBuffer.toString();
  } catch (Exception ex) {
  ex.printStackTrace();
  return "";
  }
  }
  public static void main(String[] args) {
  try {
  NioEchoServer.getInstance().start();
  } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
  }
  }

發佈了18 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章