Java中BIO、NIO和AIO的區別、原理與用法

IO

什麼是IO? 它是指計算機與外部世界或者一個程序與計算機的其餘部分的之間的接口。它對於任何計算機系統都非常關鍵,因而所有 I/O 的主體實際上是內置在操作系統中的。單獨的程序一般是讓系統為它們完成大部分的工作。

在 Java 編程中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被視為單個的字節的移動,通過一個稱為 Stream 的對象一次移動一個字節。流 I/O 用於與外部世界接觸。它也在內部使用,用於將對象轉換為字節,然後再轉換回對象。

BIO

Java BIO即Block I/O , 同步並阻塞的IO。

BIO就是傳統的java.io包下面的代碼實現。

NIO

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

面向流 的 I/O 系統一次一個字節地處理數據。一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據。為流式數據創建過濾器非常容易。鏈接幾個過濾器,以便每個過濾器隻負責單個復雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。

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

AIO

Java AIO即Async非阻塞,是異步非阻塞的IO。

區別及聯系

  • BIO (Blocking I/O):同步阻塞I/O模式,數據的讀取寫入必須阻塞在一個線程內等待其完成。這裡假設一個燒開水的場景,有一排水壺在燒開水,BIO的工作模式就是, 叫一個線程停留在一個水壺那,直到這個水壺燒開,才去處理下一個水壺。但是實際上線程在等待水壺燒開的時間段什麼都沒有做。
  • NIO (New I/O):同時支持阻塞與非阻塞模式,但這裡我們以其同步非阻塞I/O模式來說明,那麼什麼叫做同步非阻塞?如果還拿燒開水來說,NIO的做法是叫一個線程不斷的輪詢每個水壺的狀態,看看是否有水壺的狀態發生瞭改變,從而進行下一步的操作。
  • AIO ( Asynchronous I/O):異步非阻塞I/O模型。異步非阻塞與同步非阻塞的區別在哪裡?異步非阻塞無需一個線程去輪詢所有IO操作的狀態改變,在相應的狀態改變後,系統會通知對應的線程來處理。對應到燒開水中就是,為每個水壺上面裝瞭一個開關,水燒開之後,水壺會自動通知我水燒開瞭。

各自適用場景

  • 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);
			System.out.println("限制是:" + bf.limit() + "容量是:" + bf.capacity()
					+ "位置是:" + bf.position());
			int length = -1;
 
			while ((length = channel.read(bf)) != -1) {
 
				/*
				 * 註意,讀取後,將位置置為0,將limit置為容量, 以備下次讀入到字節緩沖中,從0開始存儲
				 */
				bf.clear();
				byte[] bytes = bf.array();
				System.out.write(bytes, 0, length);
				System.out.println();
 
				System.out.println("限制是:" + bf.limit() + "容量是:" + bf.capacity()
						+ "位置是:" + bf.position());
 
			}
 
			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("你好你好你好你好你好");
			// 字節緩沖的容量和limit會隨著數據長度變化,不是固定不變的
			System.out.println("初始化容量和limit:" + src.capacity() + ","
					+ src.limit());
			int length = 0;
 
			while ((length = channel.write(src)) != 0) {
				/*
				 * 註意,這裡不需要clear,將緩沖中的數據寫入到通道中後 第二次接著上一次的順序往下讀
				 */
				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);
 
  }
}

到此這篇關於Java中BIO、NIO和AIO的區別、原理與用法的文章就介紹到這瞭。希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: