/* 字節(jié)IO */ public void byteIO() throws FileNotFoundException, IOException { FileInputStream fin = new FileInputStream(new File( "D://test//byteio_in.txt")); FileOutputStream fout = new FileOutputStream(new File( "D://test//byteio_out.txt")); int c = -1; while ((c = fin.read()) != -1) { fout.write(c); } fin.close(); fout.close(); } /* 字符IO */ public void charIO() throws FileNotFoundException, IOException { FileReader reader = new FileReader(new File("D://test//chario_in.txt", "")); FileWriter writer = new FileWriter(new File("D://test//chario_out.txt")); char[] charArr = new char[512]; while (reader.read(charArr) != -1) { writer.write(charArr); } reader.close(); writer.close(); } /* bufferIO */ public void bufferIO() throws FileNotFoundException, IOException { BufferedInputStream bufferReader = new BufferedInputStream( new FileInputStream("D://test//bufferio_in.txt")); BufferedOutputStream bufferWriter = new BufferedOutputStream( new FileOutputStream("D://test//bufferio_out.txt")); int c = -1; while ((c = bufferReader.read()) != -1) { bufferWriter.write(c); } bufferReader.close(); bufferWriter.close(); }
/* NIO */ public void NIO() throws FileNotFoundException, IOException { FileInputStream fin = new FileInputStream("D://test//nio_in.txt"); FileOutputStream fout = new FileOutputStream("D://test//nio_out.txt"); FileChannel finChannel = fin.getChannel(); FileChannel foutChannel = fout.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(512); while (finChannel.read(buffer) != 1)//讀到緩存 { buffer.flip();//指針跳到緩存頭 foutChannel.write(buffer); buffer.clear();//重置緩沖區(qū) } fin.close(); fout.close(); }
java自1.4以后,加入了新IO特性NIO,NIO帶來了non-blocking特性。
在之前的服務(wù)器處理模型中,在調(diào)用ServerSocket.accept()方法時,會一直阻塞到有客戶端連接才會返回,每個客戶端連接過來后,服務(wù)端都會accept一個新連接,接著啟動一個線程去處理該客戶端的請求。在這個新的線程中,也會在read()方法中阻塞,直到讀取完數(shù)據(jù)。
這樣會有什么問題呢?
阻塞導(dǎo)致大量線程資源被浪費;阻塞可導(dǎo)致大量的上下文切換,很多切換其實是無意義的
那么NIO是如何幫助我們解決這種問題的呢?
1). 由一個專門的線程來處理所有的 IO 事件,并負責(zé)分發(fā)。
2). 事件驅(qū)動機制:事件到的時候觸發(fā),而不是同步的去監(jiān)視事件。
3). 線程通訊:線程之間通過 wait,notify 等方式通訊。保證每次上下文切換都是有意義的。減少無謂的線程切換。
服務(wù)端和客戶端各自維護一個管理通道的對象,我們稱之為selector,該對象能檢測一個或多個通道 (channel) 上的事件。我們以服務(wù)端為例,如果服務(wù)端的selector上注冊了讀事件,某時刻客戶端給服務(wù)端發(fā)送了一些數(shù)據(jù),NIO的服務(wù)端會在selector中添加一個讀事件。服務(wù)端的處理線程會輪詢地訪問selector,如果訪問selector時發(fā)現(xiàn)有感興趣的事件到達,則處理這些事件,如果沒有感興趣的事件到達,則處理線程會一直阻塞直到感興趣的事件到達為止。
下面是一個NIO實現(xiàn)Server的例子
public class MultiPortEcho { PRivate int ports[]; private ByteBuffer echoBuffer = ByteBuffer.allocate(1024); public MultiPortEcho(int ports[]) throws IOException { this.ports = ports; go(); } private void go() throws IOException { // Create a new selector Selector selector = Selector.open(); // Open a listener on each port, and register each one with the selector for (int i = 0; i < ports.length; ++i) { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); ServerSocket ss = ssc.socket(); InetSocketAddress address = new InetSocketAddress(ports[i]); ss.bind(address); SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Going to listen on " + ports[i]); } while (true) { int num = selector.select(); Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) { // Accept the new connection ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); // Add the new connection to the selector SelectionKey newKey = sc.register(selector,SelectionKey.OP_READ); it.remove(); System.out.println("Got connection from " + sc); } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { // Read the data SocketChannel sc = (SocketChannel) key.channel(); // Echo data int bytesEchoed = 0; while (true) { echoBuffer.clear(); int r = sc.read(echoBuffer); if (r <= 0) { break; } echoBuffer.flip(); sc.write(echoBuffer); bytesEchoed += r; } System.out.println("Echoed " + bytesEchoed + " from " + sc); it.remove(); } } } } static public void main(String args[]) throws Exception { int ports[] = {1234,6765,7987}; for (int i = 0; i < args.length; ++i) { ports[i] = Integer.parseInt(args[i]); } new MultiPortEcho(ports); }}
參考資料:
http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html#ibm-pcon
http://weixiaolu.VEvb.com/blog/1479656
新聞熱點
疑難解答