最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java的三種IO模型詳解(BIO、NIO、AIO)

 更新時間:2024年11月28日 09:43:51   作者:BLUcoding  
本文介紹了BIO、NIO和AIO三種不同的IO模型,分別分析了它們的工作機(jī)制、實現(xiàn)方式以及與BIO的對比,BIO是阻塞的,每個連接需要一個線程;NIO是同步非阻塞的,通過緩沖區(qū)和選擇器實現(xiàn)I/O多路復(fù)用;AIO是異步的,操作系統(tǒng)處理IO操作,完成后通知應(yīng)用程序

一、BIO 阻塞式 IO(Blocking IO)

每個客戶端連接都會在一個獨(dú)立的線程中處理,并且這個線程在處理 IO 操作時會阻塞,直到操作完成。

  • 每個連接都需要一個獨(dú)立的線程,連接數(shù)較多時,會消耗大量的內(nèi)存和 CPU 資源
  • 線程在處理 IO 操作時會阻塞

1.1、BIO 工作機(jī)制

  • 客戶端通過 Socket 對象與服務(wù)端建立連接,從 Socket 中得到字節(jié)輸入流或輸出流進(jìn)行數(shù)據(jù)讀寫。
  • 服務(wù)端通過 ServerSocket 注冊端口,調(diào)用 accept 方法監(jiān)聽客戶端 Socket 請求,從 Socket 中得到字節(jié)輸入流或輸出流進(jìn)行數(shù)據(jù)讀寫。

1.2、BIO 實現(xiàn)單發(fā)單收

客戶端:

public static void main(String[] args) {
	Socket socket = null;
	try {
		//與服務(wù)端連接
		socket = new Socket("127.0.0.1", 5000);
		//從 socket 管道中獲取字節(jié)輸出流
		OutputStream os = socket.getOutputStream();
		//將字節(jié)輸出流包裝為打印流
		PrintStream ps = new PrintStream(os);
		//發(fā)一行數(shù)據(jù)
		ps.println("Hi BIO! 與服務(wù)端通信成功");
		ps.flush();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

服務(wù)端:

 public static void main(String[] args) {
 	System.out.println("===服務(wù)端啟動===");
 	ServerSocket serverSocket = null;
 	try {
 		//注冊端口
		serverSocket = new ServerSocket(5000);
		//監(jiān)聽客戶端請求
		Socket socket = serverSocket.accept();
		//從 socket 管道中獲取字節(jié)輸入流
		InputStream is = socket.getInputStream();
		//將字節(jié)輸入流包裝為緩沖字符輸入流
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		
		String msg;
		//讀一行數(shù)據(jù)
		if ((msg = br.readLine()) != null) {
			System.out.println("服務(wù)端接收客戶端信息為:" + msg);
		}
	}catch (Exception e){
		System.out.println(e.getMessage());
	}
}

1.3、BIO 實現(xiàn)多發(fā)多收

客戶端:

public static void main(String[] args) {
    try {
        Socket socket = new Socket("localhost",9988);
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("請輸入:");
            String input = scanner.nextLine();
            ps.println(input);
            ps.flush();
        }
     } catch (IOException e) {
     	e.printStackTrace();
     }
}

服務(wù)端:

public static void main(String[] args) {
    System.out.println("===服務(wù)端啟動===");
    try {
         ServerSocket ss = new ServerSocket(9988);
         Socket socket = ss.accept();
         InputStream is = socket.getInputStream();
         BufferedReader br = new BufferedReader(new InputStreamReader(is));
         String message;
         while ((message = br.readLine()) != null){
             System.out.println("服務(wù)端接收客戶端信息為:" + message);
         }
     } catch (IOException e) {
		e.printStackTrace();
     }
}

1.4、BIO 實現(xiàn)客戶端服務(wù)端多對一

服務(wù)端:

public void listen() throws IOException {
	ServerSocket serverSocket = null;
	try {
		log.info("服務(wù)啟動監(jiān)聽");
		serverSocket = new ServerSocket(9988);
		//循環(huán)接收到客戶端的連接
		while (true) {
			Socket socket = serverSocket.accept();
			//得到連接后,開啟一個線程處理連接
			handleSocket(socket);
		}
	} finally {
		if(serverSocket != null){
			serverSocket.close();
		}
	}
}

private void handleSocket(Socket socket) {
	HandleSocket socketHandle = new HandleSocket(socket);
	new Thread(socketHandle).start();
}
public void run() {
	BufferedInputStream bufferedInputStream = null;
	BufferedOutputStream bufferedOutputStream  = null;
	try {
		bufferedInputStream = new BufferedInputStream(socket.getInputStream());
		byte[] bytes = new byte[1024];
		int len ;
		if ((len = bufferedInputStream.read(bytes)) > -1) {
			String result = new String(bytes,0,len);
            System.out.println("本次接收到的結(jié)果:" + result);
        }
        System.out.println("回復(fù)信息給客戶端:");
        bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        String outString = Thread.currentThread().getName() + "接收到了";
        bufferedOutputStream.write(outString.getBytes());
        bufferedOutputStream.flush();
	} catch (IOException e) {
		System.out.println("處理異常:" + e.getMessage());
	} finally {
		try {
			if (bufferedInputStream != null) {
				bufferedInputStream.close();
			}
			if (bufferedOutputStream != null) {
				bufferedOutputStream.close();
			}
		}catch (IOException e){
			System.out.println("關(guān)閉流異常:" + e.getMessage());
		}
	}
}

客戶端:

public void start() throws IOException {
	Socket socket = new Socket("127.0.0.1", 8081);
	String msg = "Hi,This is the BioClient";
	BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
	byte[] bytes = msg.getBytes();
	bufferedOutputStream.write(bytes);
	bufferedOutputStream.flush();
	System.out.println("發(fā)送完畢");
	BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
	byte[] inBytes = new byte[1024];
	int len;
	if ((len = bufferedInputStream.read(inBytes)) != -1) {
		String result = new String(inBytes, 0, len);
		System.out.println("接收到的消息="+result);
	}
	bufferedOutputStream.close();
	bufferedInputStream.close();
	socket.close();
}

1.5、BIO 模式下的端口轉(zhuǎn)發(fā)思想

一個客戶端的消息經(jīng)由服務(wù)端發(fā)送給所有的客戶端,實現(xiàn)群聊功能。

public class Server {

    // 定義一個靜態(tài)集合
    public static List<Socket> allSocketOnLine = new ArrayList();

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(9999);
            while (true){
                Socket socket = ss.accept();
                // 把登錄的客戶端socket存入到一個在線的集合中去
                allSocketOnLine.add(socket);
                // 為當(dāng)前登錄成功的socket分配一個獨(dú)立的線程來處理
                new ServerReaderThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

public class ServerReaderThread extends Thread{

    private Socket socket;
    
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    
    @Override
    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String msg;
            while ((msg = br.readLine()) != null) {
                // 發(fā)送給所有的在線socket
                sendMsgToAllClient(msg);
            }
        } catch (Exception e) {
            System.out.println("有人下線了");
            Server.allSocketOnLine.remove(socket);
        }

    }

    /**
     * 把當(dāng)前客戶端發(fā)來的消息發(fā)送給全部的在線socket
     * @param msg
     */
    private void sendMsgToAllClient(String msg) throws IOException {
        for (Socket sk : Server.allSocketOnLine) {
            PrintWriter pw = new PrintWriter(sk.getOutputStream());
            pw.println(msg);
            pw.flush();
        }
    }
    
}

二、NIO 同步非阻塞式 IO(Non-blocking IO)

允許線程在等待IO操作完成期間可以繼續(xù)執(zhí)行其他任務(wù)。

2.1、NIO 3個核心組件(緩沖區(qū)、通道、選擇器)

  • 緩沖區(qū)(Buffer):用于存儲數(shù)據(jù)的對象。數(shù)據(jù)從通道讀取到緩沖區(qū),或者從緩沖區(qū)寫入到通道。
  • 通道(Channel):既可以從通道中讀取數(shù)據(jù),又可以寫數(shù)據(jù)到通道
  • 選擇器(Selector):同時管理多個通道,通過注冊通道的事件(如連接就緒、讀就緒、寫就緒),使用單個線程就能處理多個通道,從而管理多個網(wǎng)絡(luò)連接,提高了效率。

2.2、NIO 主要特性

  • 非阻塞I/O:允許線程在等待IO操作完成期間可以繼續(xù)執(zhí)行其他任務(wù)
  • IO多路復(fù)用:通過選擇器,NIO允許多個通道共用一個線程進(jìn)行管理,減少了線程的資源消耗。
  • 異步IO操作:可以在通道上注冊事件和回調(diào)函數(shù),實現(xiàn)非阻塞的IO操作
  • 內(nèi)存映射文件:將文件的一部分或全部直接映射到內(nèi)存中,這樣可以像訪問內(nèi)存一樣訪問文件,提高了文件處理的效率。
  • 文件鎖定:允許對文件的部分或全部進(jìn)行鎖定,從而控制對文件的并發(fā)訪問。

2.3、NIO 與 BIO 的對比

  • 面向流與面向緩沖:BIO 是面向流的,每次從流中讀一個或多個字節(jié),直至讀取所有字節(jié);而 NIO 是面向緩沖區(qū)的。
  • 阻塞與非阻塞:BIO 的流是阻塞的,當(dāng)一個線程調(diào)用 read()write() 時,該線程被阻塞,直到有一些數(shù)據(jù)被讀取或數(shù)據(jù)完全寫入;而 NIO 是非阻塞的,一個線程從某通道發(fā)送請求讀取數(shù)據(jù),它僅能得到目前可用的數(shù)據(jù),如果目前沒有數(shù)據(jù)可用時,就什么都不會獲取。
  • 線程開銷:BIO 為每個客戶端連接創(chuàng)建一個線程,在大量并發(fā)連接的情況下會帶來巨大的線程開銷;NIO 通過選擇器實現(xiàn) I/O多路復(fù)用,在一個線程中處理多個通道,減少了線程開銷。

2.4、Buffer 常用子類

  • ByteBuffer:用于存儲字節(jié)數(shù)據(jù);
  • CharBuffer:用于存儲字符數(shù)據(jù);
  • ShortBuffer:用于存儲Short類型數(shù)據(jù);
  • IntBuffer:用于存儲Int類型數(shù)據(jù);
  • LongBuffer:用于存儲Long類型數(shù)據(jù);
  • FloatBuffer:用于存儲Float類型數(shù)據(jù);
  • DoubleBuffer:用于存儲Double類型數(shù)據(jù);

2.5、Buffer 重要屬性

  • capacity(容量):表示 Buffer 所占的內(nèi)存大小,不能為負(fù)且創(chuàng)建后不能更改
  • limit(限制):表示 Buffer 中可以操作數(shù)據(jù)的大小,不能為負(fù)且不能大于 capacity
    寫模式下,表示最多能往 Buffer 里寫多少數(shù)據(jù),即 limit 等于 capacity
    讀模式下,表示最多能讀到多少數(shù)據(jù),即已寫入的所有數(shù)據(jù)
  • position(位置):表示下一個要讀取或?qū)懭氲臄?shù)據(jù)的索引
    緩沖區(qū)位置不能為負(fù),且不能大于其限制
    初始 position 值為 0,最大為 capacity – 1。當(dāng)一個 byte、long 等數(shù)據(jù)寫到 Buffer 后, position 會向前移動到下一個可插入數(shù)據(jù)的 Buffer 單元
  • mark(標(biāo)記):表示記錄當(dāng)前 position 的位置,可通過 reset() 恢復(fù)到 mark 的位置

三、AIO 異步式 IO(Asynchronous IO)

異步式IO操作不會阻塞線程,而是交由操作系統(tǒng)處理。

完成后,操作系統(tǒng)會通知應(yīng)用程序,或者應(yīng)用程序主動查詢完成狀態(tài)。

使線程在等待IO完成的同時可以執(zhí)行其他任務(wù),提高了系統(tǒng)的并發(fā)性能。

3.1、AIO 核心組件(異步通道、完成處理器)

1.異步通道(Asynchronous Channel):AIO 中進(jìn)行I/O操作的基礎(chǔ)設(shè)施。

AIO提供了多種異步通道:

  • AsynchronousSocketChannel(異步套接字通道,支持面向連接的網(wǎng)絡(luò)通信)
  • AsynchronousServerSocketChannel(異步服務(wù)器套接字通道,支持異步服務(wù)器端套接字通信)
  • AsynchronousFileChannel(異步文件通道,支持異步文件讀寫操作)

2.完成處理器(Completion Handler):用于在I/O操作完成后處理結(jié)果的回調(diào)接口。

完成處理器包含兩個方法:

  • completed(V result, A attachment) 在I/O操作成功完成時調(diào)用;
  • failed(Throwable exc, A attachment) 在I/O操作失敗時調(diào)用。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 利用maven-shade-plugin插件解決不兼容的依賴沖突的情況

    利用maven-shade-plugin插件解決不兼容的依賴沖突的情況

    本文介紹了在Maven工程中遇到底層依賴包版本沖突問題,使用maven-shade-plugin插件解決沖突的方法,并詳細(xì)描述了步驟及注意事項
    2026-05-05
  • Tornadofx學(xué)習(xí)筆記之IconTextFx開源庫整合5000+個字體圖標(biāo)

    Tornadofx學(xué)習(xí)筆記之IconTextFx開源庫整合5000+個字體圖標(biāo)

    這篇文章主要介紹了Tornadofx學(xué)習(xí)筆記之IconTextFx開源庫整合5000+個字體圖標(biāo)的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • Java反射機(jī)制基礎(chǔ)詳解

    Java反射機(jī)制基礎(chǔ)詳解

    這篇文章主要介紹了JAVA 反射機(jī)制的相關(guān)知識,文中講解的非常細(xì)致,代碼幫助大家更好的理解學(xué)習(xí),感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • Java集合框架實戰(zhàn)HashMap與HashSet的使用案例

    Java集合框架實戰(zhàn)HashMap與HashSet的使用案例

    本文通過兩個案例詳細(xì)介紹了HashMap和HashSet在Java中的應(yīng)用,通過這些案例,我們學(xué)習(xí)了如何選擇合適的集合類型、重寫equals和hashCode方法、利用泛型和并發(fā)集合等最佳實踐,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • java導(dǎo)出Excel通用方法的實例詳解

    java導(dǎo)出Excel通用方法的實例詳解

    這篇文章主要介紹了java導(dǎo)出Excel通用方法的實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • java使用poi導(dǎo)出Excel的方法

    java使用poi導(dǎo)出Excel的方法

    這篇文章主要為大家詳細(xì)介紹了java使用poi導(dǎo)出Excel的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫

    Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫

    這篇文章主要介紹了Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫,代碼簡潔,使用簡單,擴(kuò)展性強(qiáng),結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • Java樹形結(jié)構(gòu)遞歸查詢方式

    Java樹形結(jié)構(gòu)遞歸查詢方式

    文章介紹了Java中實現(xiàn)樹形結(jié)構(gòu)遞歸查詢的方法,首先找出所有的根節(jié)點(diǎn),然后通過循環(huán)遍歷根節(jié)點(diǎn),找到每個根節(jié)點(diǎn)的子節(jié)點(diǎn),最終構(gòu)建完整的樹形結(jié)構(gòu),這是一種有效的遞歸查詢思路,適用于需要層次化展示數(shù)據(jù)的場景
    2024-12-12
  • mybatis中的擴(kuò)展實現(xiàn)源碼解析

    mybatis中的擴(kuò)展實現(xiàn)源碼解析

    這篇文章主要介給大家紹了關(guān)于mybatis中擴(kuò)展實現(xiàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • springboot vue組件開發(fā)實現(xiàn)接口斷言功能

    springboot vue組件開發(fā)實現(xiàn)接口斷言功能

    這篇文章主要為大家介紹了springboot+vue組件開發(fā)實現(xiàn)接口斷言功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05

最新評論

巴塘县| 石城县| 永顺县| 汽车| 清涧县| 大姚县| 陕西省| 尼木县| 澄迈县| 铁岭市| 庆城县| 新丰县| 承德县| 辰溪县| 宁武县| 新化县| 吴堡县| 孝义市| 韶关市| 永平县| 阳城县| 民权县| 田林县| 察隅县| 黄骅市| 拜泉县| 临朐县| 临高县| 郁南县| 阆中市| 山西省| 太仓市| 峡江县| 内黄县| 凤冈县| 修文县| 兴义市| 沙田区| 定边县| 宜兰县| 兴和县|