漫話:如何給女友解釋什麼是BIO、NIO和AIO?


週末午後,在家裏面進行電話面試,我問了面試者幾個關於IO的問題,其中包括什麼是BIO、NIO和AIO?三者有什麼區別?具體如何使用等問題,可是面試者回答的並非很滿意。因而我在面試評價中寫道:"對Java的IO提醒理解不夠深刻"。剛好被女友看到了。面試

Java IO

IO,常寫做I/O,是Input/Output的簡稱,即輸入/輸出。一般指數據在內部存儲器(內存)和外部存儲器(硬盤、優盤等)或其餘周邊設備之間的輸入和輸出。編程

輸入/輸出是信息處理系統(例如計算機)與外部世界(多是人類或另外一信息處理系統)之間的通訊。bash

輸入是系統接收的信號或數據,輸出則是從其發送的信號或數據。服務器

在Java中,提供了一些列API,能夠供開發者來讀寫外部數據或文件。咱們稱這些API爲Java IO。網絡

IO是Java中比較重要,且比較難的知識點,主要是由於隨着Java的發展,目前有三種IO共存。分別是BIO、NIO和AIO。架構

Java BIO

BIO 全稱Block-IO 是一種同步且阻塞的通訊模式。是一個比較傳統的通訊方式,模式簡單,使用方便。但併發處理能力低,通訊耗時,依賴網速。併發

Java NIO

Java NIO,全程 Non-Block IO ,是Java SE 1.4版之後,針對網絡傳輸效能優化的新功能。是一種非阻塞同步的通訊模式。異步

NIO 與原來的 I/O 有一樣的做用和目的, 他們之間最重要的區別是數據打包和傳輸的方式。原來的 I/O 以流的方式處理數據,而 NIO 以塊的方式處理數據。async

面向流的 I/O 系統一次一個字節地處理數據。一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據。ide

面向塊的 I/O 系統以塊的形式處理數據。每個操做都在一步中產生或者消費一個數據塊。按塊處理數據比按(流式的)字節處理數據要快得多。可是面向塊的 I/O 缺乏一些面向流的 I/O 所具備的優雅性和簡單性。

Java AIO

Java AIO,全程 Asynchronous IO,是異步非阻塞的IO。是一種非阻塞異步的通訊模式。

在NIO的基礎上引入了新的異步通道的概念,並提供了異步文件通道和異步套接字通道的實現。

三種IO的區別

首先,咱們站在宏觀的角度,從新畫一下重點:

BIO (Blocking I/O):同步阻塞I/O模式。

NIO (New I/O):同步非阻塞模式。

AIO (Asynchronous I/O):異步非阻塞I/O模型。

那麼,同步阻塞、同步非阻塞、異步非阻塞都是怎麼回事呢?關於這部份內容也能夠查看《漫話:如何給女友解釋什麼是IO中的阻塞、非阻塞、同步、異步?》。

同步阻塞模式:這種模式下,咱們的工做模式是先來到廚房,開始燒水,並坐在水壺面前一直等着水燒開。

同步非阻塞模式:這種模式下,咱們的工做模式是先來到廚房,開始燒水,可是咱們不一直坐在水壺前面等,而是回到客廳看電視,而後每隔幾分鐘到廚房看一下水有沒有燒開。

異步非阻塞I/O模型:這種模式下,咱們的工做模式是先來到廚房,開始燒水,咱們不一一直坐在水壺前面等,也不隔一段時間去看一下,而是在客廳看電視,水壺上面有個開關,水燒開以後他會通知我。

阻塞VS非阻塞:人是否坐在水壺前面一直等。

同步VS異步:水壺是否是在水燒開以後主動通知人。

適用場景

BIO方式適用於鏈接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4之前的惟一選擇,但程序直觀簡單易理解。

NIO方式適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。

AIO方式適用於鏈接數目多且鏈接比較長(重操做)的架構,好比相冊服務器,充分調用OS參與併發操做,編程比較複雜,JDK7開始支持。

使用方式

使用BIO實現文件的讀取和寫入。

//Initializes The Object
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);

//Write Obj to File
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
    oos.writeObject(user);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(oos);
}

//Read Obj from File
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(file));
    User1 newUser = (User1) ois.readObject();
    System.out.println(newUser);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(ois);
    try {
        FileUtils.forceDelete(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//Initializes The Object
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);

//Write Obj to File
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
    oos.writeObject(user);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(oos);
}

//Read Obj from File
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(file));
    User1 newUser = (User1) ois.readObject();
    System.out.println(newUser);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(ois);
    try {
        FileUtils.forceDelete(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
複製代碼

使用NIO實現文件的讀取和寫入。

static void readNIO() {
        String pathname = "C:\\Users\\adew\\Desktop\\jd-gui.cfg";
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(new File(pathname));
            FileChannel channel = fin.getChannel();

            int capacity = 100;// 字節
            ByteBuffer bf = ByteBuffer.allocate(capacity);
            int length = -1;

            while ((length = channel.read(bf)) != -1) {

                bf.clear();
                byte[] bytes = bf.array();
                System.out.write(bytes, 0, length);
                System.out.println();
            }

            channel.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fin != null) {
                try {
                    fin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static void writeNIO() {
        String filename = "out.txt";
        FileOutputStream fos = null;
        try {

            fos = new FileOutputStream(new File(filename));
            FileChannel channel = fos.getChannel();
            ByteBuffer src = Charset.forName("utf8").encode("你好你好你好你好你好");
            int length = 0;

            while ((length = channel.write(src)) != 0) {
                System.out.println("寫入長度:" + length);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
複製代碼

使用AIO實現文件的讀取和寫入

public class ReadFromFile {
  public static void main(String[] args) throws Exception {
    Path file = Paths.get("/usr/a.txt");
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    Future<Integer> result = channel.read(buffer, 0);

    while (!result.isDone()) {
      ProfitCalculator.calculateTax();
    }
    Integer bytesRead = result.get();
    System.out.println("Bytes read [" + bytesRead + "]");
  }
}
class ProfitCalculator {
  public ProfitCalculator() {
  }
  public static void calculateTax() {
  }
}

public class WriteToFile {

  public static void main(String[] args) throws Exception {
    AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
        Paths.get("/asynchronous.txt"), StandardOpenOption.READ,
        StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() {

      @Override
      public void completed(Integer result, Object attachment) {
        System.out.println("Attachment: " + attachment + " " + result
            + " bytes written");
        System.out.println("CompletionHandler Thread ID: "
            + Thread.currentThread().getId());
      }

      @Override
      public void failed(Throwable e, Object attachment) {
        System.err.println("Attachment: " + attachment + " failed with:");
        e.printStackTrace();
      }
    };

    System.out.println("Main Thread ID: " + Thread.currentThread().getId());
    fileChannel.write(ByteBuffer.wrap("Sample".getBytes()), 0, "First Write",
        handler);
    fileChannel.write(ByteBuffer.wrap("Box".getBytes()), 0, "Second Write",
        handler);

  }
}
複製代碼

滴滴滴,水開了。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息