Java NIO

I/O簡介 

  I/O問題能夠說是當今web應用中所面臨的的主要問題之一,大部分的web應用系統的瓶頸都是I/O瓶頸。這個系列主要介紹JAVA的I/O類庫基本架構、磁盤I/O工做機制、網絡I/O工做機制以及NIO的工做方式。java

BIO(Block IO)和Nio(Non-Block IO)的對比

IO模式 BIO NIO
方式 從磁盤到磁盤 從緩存到磁盤
通訊 緩存(多級複用)
處理 阻塞 非阻塞(Reactor)
觸發 選擇器輪詢機制

 

從1.4版本開始JAVA引入了NIO,用來提高I/O性能。I/O操做類在包java.io下,大概有將近80個類web

這些類能夠分爲以下四組:數組

  基於字節操做的I/O接口:InputStream和OutputStream緩存

  基於字符操做的I/O接口:Reader和Writer網絡

  基於磁盤操做的I/O接口:File架構

  基於網絡操做的I/O接口:Socket異步

前兩組是傳輸數據的格式,後兩組是傳輸數據的方式socket

核心組件

核心組件 定義 做用 特色 使用

通道性能

(Channel)大數據

NIO數據的源頭/目的地

(Buffer的惟一接口)

向緩存提供數據

讀取換區的數據

雙向讀寫,異步讀寫

數據來源/流向 老是Buffer

根據來源區別:

FileChannel:從文件

DataChannel:從UDP網絡數據

SocketChannel:

ServerSocketChannel

緩存

(Buffer)

NIO數據讀/寫中轉地

(一塊完整的內存塊)

數據緩存 適用於處布爾外基本數據類型

7種基本數據類型

 

選擇器

(Selector)

異步IO核心類 實現異步非阻塞IO

使用一個Selector線程檢測1個/多個

通道channel上的事件,給予事件驅動

分發不須要爲每一個channel去分配一個線程

一、建立Selector對象

二、箱Slector註冊通道Channel

二、調用Selector類中select()方法

1、Buffer緩存區

1) Buffer介紹: 緩衝區,本質就是一個數組,可是它是特殊的數組,緩衝區對象內置了一些機制,可以追蹤和記錄緩衝區的狀態變化狀況,若是咱們使用get方法從   緩衝區中獲取數據或者用put方法吧數據寫入緩衝區,都會引發緩衝區的狀態變化
在緩衝區中,最重要的屬性是以下三個,他們一塊兒合做完成了對緩衝區內容狀態的變化跟蹤
1)position:指定了下一個將要被寫入或者讀取的元素索引,它的值由get()/put() 方法自動更新,在新建立一個Buffer對象時,position被初始化爲0
2)limit:操做緩衝區的可操做空間和可操做範圍,指定還有多少數據須要去除,或者還有多少空間能夠放入數據
3)capacity:指定了能夠存儲在緩衝區中的最大數據容量,實際上,它指定了底層數組的大小,或者至少是指定了准許咱們使用的底層數組的容量。

以上三個屬性值之間有一些相對的大小的關係:0<=position<=limit<=capacity

package com.Allen.buffer;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class testBufferDemo01 {
    public static void main(String[] args) throws IOException {
        String fileURL="F://a.txt";
        FileInputStream fis=new FileInputStream(fileURL);
        //獲取通路
        FileChannel channel=fis.getChannel();
        //定義緩衝區大小
        ByteBuffer buffer=ByteBuffer.allocate(10);
        output("init", buffer);
        //先讀
        channel.read(buffer);
        output("read", buffer);
        buffer.flip();
        output("flip", buffer);        
        while (buffer.hasRemaining()) {
            byte b=buffer.get();
        }
        output("get", buffer);
        buffer.clear();
        output("clear", buffer);
        fis.close();
    }
    
    public static void output(String string,ByteBuffer buffer){
        System.out.println(string);
        System.out.println(buffer.capacity()+":"+buffer.position()+":"+buffer.limit());
    }
}

2、Channel(通路)

任什麼時候候讀取數據,都不是直接從通道中讀取,而是從通道讀取到緩衝區,因此使用NIO讀取數據能夠分紅下面三個步驟
1)從FileInputStream獲取Channel
2)建立Buffer
3)將數據從Channel 讀取到Buffer中

package com.allen.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class testNio {
    public static void main(String[] args) throws IOException {
        String oldFileUrl="E://1.txt";
        String newFileUrl="E://2.txt";
        FileInputStream fis=new FileInputStream(oldFileUrl);
     //一、獲取Channel FileChannel inChannel
=fis.getChannel();
     //二、建立Buffer ByteBuffer bf
=ByteBuffer.allocate(1024); FileOutputStream fos=new FileOutputStream(newFileUrl); FileChannel outChannel=fos.getChannel(); while(true){ int eof=inChannel.read(bf); if(eof==-1){ break; }else{ bf.flip();
     //三、把數據寫入緩存 outChannel.write(bf); bf.clear(); } } inChannel.close(); fis.close(); outChannel.close(); fos.close(); } }

3、Selector(選擇器)

  Selector 通常稱 爲選擇器 ,也即多路複用器 。它是Java NIO核心組件中的一個,用於檢查一個或多個NIO Channel(通道)的狀態是否處於可讀、可寫。如此能夠實現單線程管理多個channels,也就是能夠管理多個網絡連接。
   使用Selector的好處: 使用更少的線程來就能夠來處理通道了, 相比使用多個線程,避免了線程上下文切換帶來的開銷。
 // 1. 建立Selector對象   
 Selector sel = Selector.open();

 // 2. 向Selector對象綁定通道   
 // a. 建立可選擇通道,並配置爲非阻塞模式   
 ServerSocketChannel server = ServerSocketChannel.open();   
 server.configureBlocking(false);   
 
 // b. 綁定通道到指定端口   
 ServerSocket socket = server.socket();   
 InetSocketAddress address = new InetSocketAddress(port);   
 socket.bind(address);   
 
 // c. 向Selector中註冊感興趣的事件   
 server.register(sel, SelectionKey.OP_ACCEPT);    
 return sel;

// 3. 處理事件
try {    
    while(true) { 
        // 該調用會阻塞,直到至少有一個事件就緒、準備發生 
        selector.select(); 
        // 一旦上述方法返回,線程就能夠處理這些事件
        Set<SelectionKey> keys = selector.selectedKeys(); 
        Iterator<SelectionKey> iter = keys.iterator(); 
        while (iter.hasNext()) { 
            SelectionKey key = (SelectionKey) iter.next(); 
            iter.remove(); 
            process(key); 
        }    
    }    
} catch (IOException e) {    
    e.printStackTrace();   
}

總結nio工做原理

1)由一個專門的線程去處理全部的io事件而且負責分發 2)事件驅動機制,時間到的時候觸發,而不是同步地去監聽事件 3)線程通訊,線程之間經過wait,notify等方式通訊,保證每次上下文切換都是有意義的,減小無畏的線程切換。
相關文章
相關標籤/搜索