




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第一文帶你你搞懂Java的3種IO模型目錄JavaBIOJavaNIOJavaAIO小結(jié)在Java中,一共有三種IO模型,分別是阻塞IO(BIO)、非阻塞IO(NIO)和異步IO(AIO)。
JavaBIO
JavaBIO就是Java的傳統(tǒng)IO模型,對應(yīng)了操作系統(tǒng)IO模型里的阻塞IO。
JavaBIO相關(guān)的實(shí)現(xiàn)都位于java.io包下,其通信原理是客戶端、服務(wù)端之間通過Socket套接字建立管道連接,然后從管道中獲取對應(yīng)的輸入/輸出流,最后利用輸入/輸出流對象實(shí)現(xiàn)發(fā)送/接收信息。
我們來看個Demo:
BioServer:
/**
*@Author三分惡
*@Date2025/4/30
*@DescriptionBIO服務(wù)端
publicclassBioServer{
publicstaticvoidmain(String[]args)throwsIOException{
//定義一個ServerSocket服務(wù)端對象,并為其綁定端口號
ServerSocketserver=newServerSocket(8888);
System.out.println("===========BIO服務(wù)端啟動================");
//對BIO來講,每個Socket都需要一個Thread
while(true){
//監(jiān)聽客戶端Socket連接
Socketsocket=server.accept();
newBioServerThread(socket).start();
*BIOServer線程
staticclassBioServerThreadextendsThread{
//socket連接
privateSocketsocket;
publicBioServerThread(Socketsocket){
this.socket=socket;
@Override
publicvoidrun(){
try{
//從socket中獲取輸入流
InputStreaminputStream=socket.getInputStream();
//轉(zhuǎn)換為
BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(inputStream));
Stringmsg;
//從Buffer中讀取信息,如果讀取到信息則輸出
while((msg=bufferedReader.readLine())!=null){
System.out.println("收到客戶端消息:"+msg);
//從socket中獲取輸出流
OutputStreamoutputStream=socket.getOutputStream();
PrintStreamprintStream=newPrintStream(outputStream);
//通過輸出流對象向客戶端傳遞信息
printStream.println("你好,吊毛!");
//清空輸出流
printStream.flush();
//關(guān)閉socket
socket.shutdownOutput();
}catch(IOExceptione){
e.printStackTrace();
}
BioClient
/**
*@Author三分惡
*@Date2025/4/30
*@DescriptionBIO客戶端
publicclassBioClient{
publicstaticvoidmain(String[]args)throwsIOException{
ListStringnames=Arrays.asList("帥哥","靚仔","坤坤");
//通過循環(huán)創(chuàng)建多個多個client
for(Stringname:names){
//創(chuàng)建socket并根據(jù)IP地址與端口連接服務(wù)端
Socketsocket=newSocket("127.0.0.1",8888);
System.out.println("===========BIO客戶端啟動================");
//從socket中獲取字節(jié)輸出流
OutputStreamoutputStream=socket.getOutputStream();
//通過輸出流向服務(wù)端傳遞信息
Stringhello="你好,"+name+"!";
outputStream.write(hello.getBytes());
//清空流,關(guān)閉socket輸出
outputStream.flush();
socket.shutdownOutput();
//從socket中獲取字節(jié)輸入流
InputStreaminputStream=socket.getInputStream();
BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(inputStream));
//讀取服務(wù)端消息
Stringmsg;
while((msg=bufferedReader.readLine())!=null){
System.out.println("收到服務(wù)端消息:"+msg);
inputStream.close();
outputStream.close();
socket.close();
}
先啟動BioServer,再啟動BioClient,運(yùn)行結(jié)果
===========BIO服務(wù)端啟動================
收到客戶端消息:你好,帥哥!
收到客戶端消息:你好,靚仔!
收到客戶端消息:你好,坤坤!
===========BIO客戶端啟動================
收到服務(wù)端消息:你好,吊毛!
===========BIO客戶端啟動================
收到服務(wù)端消息:你好,吊毛!
===========BIO客戶端啟動================
收到服務(wù)端消息:你好,吊毛!
在上述Java-BIO的通信過程中,如果客戶端一直沒有發(fā)送消息過來,服務(wù)端則會一直等待下去,從而服務(wù)端陷入阻塞狀態(tài)。同理,由于客戶端也一直在等待服務(wù)端的消息,如果服務(wù)端一直未響應(yīng)消息回來,客戶端也會陷入阻塞狀態(tài)。
在BioServer定義了一個類BioServerThread,繼承了Thread類,run方法里主要是通過socket和流來讀取客戶端的消息,以及發(fā)送消息給客戶端,每處理一個客戶端的Socket連接,就得新建一個線程。
同時,IO讀寫操作也是阻塞的,如果客戶端一直沒有發(fā)送消息過來,線程就會進(jìn)入阻塞狀態(tài),一直等待下去。
在BioClient里,循環(huán)創(chuàng)建Socket,向服務(wù)端收發(fā)消息,客戶端的讀寫也是阻塞的。
在這個Demo里就體現(xiàn)了BIO的兩個特點(diǎn):
一個客戶端連接對應(yīng)一個處理線程讀寫操作都是阻塞的
毫無疑問,不管是創(chuàng)建太多線程,還是阻塞讀寫,都會浪費(fèi)服務(wù)器的資源。
JavaNIO
那么我們就進(jìn)入Java的下一種IO模型JavaNIO,它對應(yīng)操作系統(tǒng)IO模型中的多路復(fù)用IO,底層采用了epoll實(shí)現(xiàn)。
Java-NIO則是JDK1.4中新引入的API,它在BIO功能的基礎(chǔ)上實(shí)現(xiàn)了非阻塞式的特性,其所有實(shí)現(xiàn)都位于java.nio包下。NIO是一種基于通道、面向緩沖區(qū)的IO操作,相較BIO而言,它能夠更為高效的對數(shù)據(jù)進(jìn)行讀寫操作,同時與原先的BIO使用方式也大有不同。
我們還是先來看個Demo:
NioServer
/**
*@Author三分惡
*@Date2025/4/30
*@DescriptionNIO服務(wù)端
publicclassNioServer{
publicstaticvoidmain(String[]args)throwsIOException{
//創(chuàng)建一個選擇器selector
Selectorselector=Selector.open();
//創(chuàng)建serverSocketChannel
ServerSocketChannelserverSocketChannel=ServerSocketChannel.open();
//綁定端口
serverSocketChannel.socket().bind(newInetSocketAddress(8888));
//必須得設(shè)置成非阻塞模式
serverSocketChannel.configureBlocking(false);
//將channel注冊到selector并設(shè)置監(jiān)聽事件為ACCEPT
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
System.out.println("===========NIO服務(wù)端啟動============");
while(true){
//超時等待
if(selector.select(1000)==0){
System.out.println("===========NIO服務(wù)端超時等待============");
continue;
//有客戶端請求被輪詢監(jiān)聽到,獲取返回的SelectionKey集合
IteratorSelectionKeyiterator=selector.selectedKeys().iterator();
//迭代器遍歷SelectionKey集合
while(iterator.hasNext()){
SelectionKeykey=iterator.next();
//判斷是否為ACCEPT事件
if(key.isAcceptable()){
//處理接收請求事件
SocketChannelsocketChannel=((ServerSocketChannel)key.channel()).accept();
//非阻塞模式
socketChannel.configureBlocking(false);
//注冊到Selector并設(shè)置監(jiān)聽事件為READ
socketChannel.register(selector,SelectionKey.OP_READ,ByteBuffer.allocate(1024));
System.out.println("成功連接客戶端");
//判斷是否為READ事件
if(key.isReadable()){
SocketChannelsocketChannel=(SocketChannel)key.channel();
try{
//獲取以前設(shè)置的附件對象,如果沒有則新建一個
ByteBufferbuffer=(ByteBuffer)key.attachment();
if(buffer==null){
buffer=ByteBuffer.allocate(1024);
key.attach(buffer);
//清空緩沖區(qū)
buffer.clear();
//將通道中的數(shù)據(jù)讀到緩沖區(qū)
intlen=socketChannel.read(buffer);
if(len0){
buffer.flip();
Stringmessage=newString(buffer.array(),0,len);
System.out.println("收到客戶端消息:"+message);
}elseif(len0){
//接收到-1,表示連接已關(guān)閉
key.cancel();
socketChannel.close();
continue;
//注冊寫事件,下次向客戶端發(fā)送消息
socketChannel.register(selector,SelectionKey.OP_WRITE,buffer);
}catch(IOExceptione){
//取消SelectionKey并關(guān)閉對應(yīng)的SocketChannel
key.cancel();
socketChannel.close();
//判斷是否為WRITE事件
if(key.isWritable()){
SocketChannelsocketChannel=(SocketChannel)key.channel();
//獲取buffer
ByteBufferbuffer=(ByteBuffer)key.attachment();
Stringhello="你好,坤坤!";
//清空buffer
buffer.clear();
//buffer中寫入消息
buffer.put(hello.getBytes());
buffer.flip();
//向channel中寫入消息
socketChannel.write(buffer);
buffer.clear();
System.out.println("向客戶端發(fā)送消息:"+hello);
//設(shè)置下次讀寫操作,向Selector進(jìn)行注冊
socketChannel.register(selector,SelectionKey.OP_READ,buffer);
//移除本次處理的SelectionKey,防止重復(fù)處理
iterator.remove();
}
NioClient
publicclassNioClient{
publicstaticvoidmain(String[]args)throwsIOException{
//創(chuàng)建SocketChannel并指定ip地址和端口號
SocketChannelsocketChannel=SocketChannel.open(newInetSocketAddress("127.0.0.1",8888));
System.out.println("==============NIO客戶端啟動================");
//非阻塞模式
socketChannel.configureBlocking(false);
Stringhello="你好,靚仔!";
ByteBufferbuffer=ByteBuffer.wrap(hello.getBytes());
//向通道中寫入數(shù)據(jù)
socketChannel.write(buffer);
System.out.println("發(fā)送消息:"+hello);
buffer.clear();
//將channel注冊到Selector并監(jiān)聽READ事件
socketChannel.register(Selector.open(),SelectionKey.OP_READ,buffer);
while(true){
//讀取服務(wù)端數(shù)據(jù)
if(socketChannel.read(buffer)0){
buffer.flip();
Stringmsg=newString(buffer.array(),0,buffer.limit());
System.out.println("收到服務(wù)端消息:"+msg);
break;
//關(guān)閉輸入流
socketChannel.shutdownInput();
//關(guān)閉SocketChannel連接
socketChannel.close();
}
先運(yùn)行NioServer,再運(yùn)行NioClient,運(yùn)行結(jié)果:
===========NIO服務(wù)端啟動============
===========NIO服務(wù)端超時等待============
===========NIO服務(wù)端超時等待============
成功連接客戶端
收到客戶端消息:你好,靚仔!
向客戶端發(fā)送消息:你好?。?/p>
==============NIO客戶端啟動================
發(fā)送消息:你好,靚仔!
收到服務(wù)端消息:你好啊!
我們在這個案例里實(shí)現(xiàn)了一個比較簡單的JavaNIO客戶端服務(wù)端通信,里面有兩個小的點(diǎn)需要注意,注冊到選擇器上的通道都必須要為非阻塞模型,同時通過緩沖區(qū)傳輸數(shù)據(jù)時,必須要調(diào)用flip()方法切換為讀取模式。
Java-NIO中有三個核心概念:Buffer(緩沖區(qū))、Channel(通道)、Selector(選擇器)。
每個客戶端連連接本質(zhì)上對應(yīng)著一個Channel通道,每個通道都有自己的Buffer緩沖區(qū)來進(jìn)行讀寫,這些Channel被Selector選擇器管理調(diào)度
Selector負(fù)責(zé)輪詢所有已注冊的Channel,監(jiān)聽到有事件發(fā)生,才提交給服務(wù)端線程處理,服務(wù)端線程不需要做任何阻塞等待,直接在Buffer里處理Channel事件的數(shù)據(jù)即可,處理完馬上結(jié)束,或返回線程池供其他客戶端事件繼續(xù)使用。
通過Selector,服務(wù)端的一個Thread就可以處理多個客戶端的請求
Buffer(緩沖區(qū))就是飯店用來存放食材的儲藏室,當(dāng)服務(wù)員點(diǎn)餐時,需要從儲藏室中取出食材進(jìn)行制作。
Channel(通道)是用于傳輸數(shù)據(jù)的車道,就像飯店里的上菜窗口,可以快速把點(diǎn)好的菜品送到客人的桌上。
Selector(選擇器)就是大堂經(jīng)理,負(fù)責(zé)協(xié)調(diào)服務(wù)員、廚師和客人的配合和溝通,以保證整個就餐過程的效率和順暢。
JavaAIO
Java-AIO也被成為NIO2,它是在NIO的基礎(chǔ)上,引入了新的異步通道的概念,并提供了異步文件通道和異步套接字的實(shí)現(xiàn)。
它們的主要區(qū)別就在于這個異步通道,見名知意:使用異步通道去進(jìn)行IO操作時,所有操作都為異步非阻塞的,當(dāng)調(diào)用read()/write()/accept()/connect()方法時,本質(zhì)上都會交由操作系統(tǒng)去完成,比如要接收一個客戶端的數(shù)據(jù)時,操作系統(tǒng)會先將通道中可讀的數(shù)據(jù)先傳入read()回調(diào)方法指定的緩沖區(qū)中,然后再主動通知Java程序去處理。
我們還是先來看個Demo:
AioServer
/**
*@Author三分惡
*@Date2025/5/1
*@DescriptionAIO服務(wù)端
publicclassAioServer{
publicstaticvoidmain(String[]args)throwsException{
//創(chuàng)建異步通道組,處理IO事件
AsynchronousChannelGroupgroup=AsynchronousChannelGroup.withFixedThreadPool(10,Executors.defaultThreadFactory());
//創(chuàng)建異步服務(wù)器Socket通道,并綁定端口
AsynchronousServerSocketChannelserver=AsynchronousServerSocketChannel.open(group).bind(newInetSocketAddress(8888));
System.out.println("=============AIO服務(wù)端啟動=========");
//異步等待接收客戶端連接
server.accept(null,newCompletionHandlerAsynchronousSocketChannel,Object(){
//創(chuàng)建ByteBuffer
finalByteBufferbuffer=ByteBuffer.allocate(1024);
@Override
publicvoidcompleted(AsynchronousSocketChannelchannel,Objectattachment){
System.out.println("客戶端連接成功");
try{
buffer.clear();
//異步讀取客戶端發(fā)送的消息
channel.read(buffer,null,newCompletionHandlerInteger,Object(){
@Override
publicvoidcompleted(Integerlen,Objectattachment){
buffer.flip();
Stringmessage=newString(buffer.array(),0,len);
System.out.println("收到客戶端消息:"+message);
//異步發(fā)送消息給客戶端
channel.write(ByteBuffer.wrap(("你好,阿坤!").getBytes()),null,newCompletionHandlerInteger,Object(){
@Override
publicvoidcompleted(Integerresult,Objectattachment){
//關(guān)閉輸出流
try{
channel.shutdownOutput();
}catch(IOExceptione){
e.printStackTrace();
@Override
publicvoidfailed(Throwableexc,Objectattachment){
exc.printStackTrace();
try{
channel.close();
}catch(IOExceptione){
e.printStackTrace();
@Override
publicvoidfailed(Throwableexc,Objectattachment){
exc.printStackTrace();
try{
channel.close();
}catch(IOExceptione){
e.printStackTrace();
}catch(Exceptione){
e.printStackTrace();
//繼續(xù)異步等待接收客戶端連接
server.accept(null,this);
@Override
publicvoidfailed(Throwableexc,Objectattachment){
exc.printStackTrace();
//繼續(xù)異步等待接收客戶端連接
server.accept(null,this);
//等待所有連接都處理完畢
group.awaitTermination(Long.MAX_VALUE,TimeUnit.SECONDS);
}
AioClient
/**
*@Author三分惡
*@Date2025/5/1
*@DescriptionAIO客戶端
publicclassAioClient{
publicstaticvoidmain(String[]args)throwsException{
//創(chuàng)建異步Socket通道
AsynchronousSocketChannelclient=AsynchronousSocketChannel.open();
//異步連接服務(wù)器
client.connect(newInetSocketAddress("127.0.0.1",8888),null,newCompletionHandlerVoid,Object(){
//創(chuàng)建ByteBuffer
finalByteBufferbuffer=ByteBuffer.wrap(("你好,靚仔!").getBytes());
@Override
publicvoidcompleted(Voidresult,Objectattachment){
//異步發(fā)送消息給服務(wù)器
client.write(buffer,null,newCompletionHandlerInteger,Object(){
//創(chuàng)建ByteBuffer
finalByteBufferreadBuffer=ByteBuffer.allocate(1024);
@Override
publicvoidcompleted(Integerresult,Objectattachment){
readBuffer.clear();
//異步讀取服務(wù)器發(fā)送的消息
client.read(readBuffer,null,newCompletionHandlerInteger,Object(){
@Override
publicvoidcompleted(Integerresult,Objectattachment){
readBuffer.flip();
Stringmsg=newString(readBuffer.array(),0,result);
System.out.println("收到服務(wù)端消息:"+msg);
@Override
publicvoidfailed(Throwableexc,Objectattachment){
exc.printStackTrace();
try{
client.close();
}catch(IOExceptione){
e.printStackTrace();
@Override
publicvoidfailed(Throwableexc,Objectattachment){
exc.printS
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高考數(shù)學(xué)實(shí)踐2024年試題及答案
- 網(wǎng)絡(luò)服務(wù)的級別試題及答案分析
- 企業(yè)競爭策略與風(fēng)險分析試題及答案
- 2025年軟考設(shè)計師備考情緒管理試題及答案
- 2025農(nóng)民土地流轉(zhuǎn)合同范本
- 2025企業(yè)租賃合同標(biāo)準(zhǔn)范文
- 棉業(yè)公司范本章程
- 法學(xué)概論研究的國際視野與試題與答案
- 班級獲獎經(jīng)驗(yàn)的總結(jié)與反思計劃
- 組織文件檔案的秘書工作計劃
- 小學(xué)蘇教版六年級下冊數(shù)學(xué)總復(fù)習(xí)《圖形的運(yùn)動》市級公開課教案
- DB62∕T 3176-2019 建筑節(jié)能與結(jié)構(gòu)一體化墻體保溫系統(tǒng)應(yīng)用技術(shù)規(guī)程
- WDM網(wǎng)絡(luò)規(guī)劃與設(shè)計指南
- 電子商務(wù)客戶服務(wù)5套綜合測試題帶答案
- 微觀經(jīng)濟(jì)學(xué)課件第二章(高鴻業(yè))
- 醫(yī)院科室6S管理制度
- 病歷書寫基本規(guī)范12021病歷書寫規(guī)范試題.doc
- 《山東省自然科學(xué)基金資助項(xiàng)目年度進(jìn)展報告》
- 電廠保安人員管理制度
- ge核磁共振機(jī)房專用精密空調(diào)機(jī)技術(shù)要求
- 發(fā)展與教育心理學(xué)個別差異
評論
0/150
提交評論