Java NIO总结.docx
- 文档编号:1635602
- 上传时间:2023-05-01
- 格式:DOCX
- 页数:17
- 大小:51.15KB
Java NIO总结.docx
《Java NIO总结.docx》由会员分享,可在线阅读,更多相关《Java NIO总结.docx(17页珍藏版)》请在冰点文库上搜索。
JavaNIO总结
NIO:
与外围设备数据通信需要channel通道,如像外部输出数据,先将数据写入缓冲区通过通道输出。
如果从外部读取数据,需要通过通道channel读取到缓冲区,然后从缓冲区数据获取处理。
缓冲区内部细节
1初始化
2第一次读取3个字节到缓冲区
3第二次读取2个字节到缓冲区
4调用Flip,将limit设置position,position设置为0
5调用clear,将limit设置为capacity,position设置为0
NIO核心观念:
通道和缓冲区(channel和Buffer)
1)块操作
2)非阻塞IO
复用机制采用select模型,注册感兴趣IO事件给操作系统后,一旦这些事件发生,内核会改变这些事件的状态,通过检查这些事件的状态,便可以查找到注册过的、准备就绪的I/O事件,然后可以流畅地进行I/O操作。
传统IO阻塞调用:
流I/O是阻塞调用的。
不论是read方法还是write方法都能阻塞(block)一个线程直到字节被真正地读取或者写入。
这意味着如果流不能立即被读取或者写入字节(通常是因为网络连接繁忙),Java就会挂起这个调用的线程,处于等待的状态。
常用Socket的读写操作都是阻塞式的,就是说每次read/write掉用,在数据被读入/写出前,调用线程都处于阻塞的状态.
多线程耗费资源,特别是多线程间切换很耗费资源。
NIO特征:
l)面向块的I/O操作
2)非阻塞的I/O操作
3)字符集编码解码
4)内存映射文件
5)文件锁定
,
Reactor模型:
Reactor模型采用分而治之的思想,将一个客户端连接的事件分成两类:
I/O事件和非I/O事件。
前者需要等待I/O准备就绪,后者可以立即执行,因此分别进行处理。
I/O事件包括:
Read(读取请求信息)、Send(发送响应信息)。
非I/O事件包括encode、compute、decode。
异步连接池:
首先,用户处理线程调用连接池对象的某个方法(比如sendRequest),把一个能够标识本次请求的Request对象扔给连接池。
之后用户处理线程可以去做别的事情,比如,向其他连接池发送请求。
最后当用户线程处理完能做的业务逻辑后,就可以等待连接池返回结果了。
(一)读写IO:
(按块缓冲区)
packagejava.nio.io;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.nio.ByteBuffer;
importjava.nio.MappedByteBuffer;
importjava.nio.channels.FileChannel;
importjava.util.Date;
/**
*@Project:
NIO
*@Title:
CopyFile.java
*@Package
*@Description:
JAVANIO读取写入文件方面优势
*@authorpaul.wei2011@
*@dateMay16,20139:
51:
13AM
*@versionV1.0
*/
//传统IO一直是性能瓶颈,因为每次按字节读取,耗费磁头寻址次数,磁头寻址时间是固定的,次数多耗费时间就长
publicclassCopyFile{
publicstaticvoidmain(String[]args)throwsException{
Stringinfile="C:
\\copy.sql";
Stringoutfile="C:
\\copy.txt";
//获取源文件和目标文件的输入输出流
FileInputStreamfin=newFileInputStream(infile);
FileOutputStreamfout=newFileOutputStream(outfile);
//获取输入输出通道
FileChannelfcin=fin.getChannel();//FileChannel对象是线程安全的
FileChannelfcout=fout.getChannel();
//每个FileChannel都有一个叫'fileposition'的概念,该position值决定文件中哪一处的数据接下来被读或写。
//FileChannelposition是从底层文件描述符获取的,当字节被read()或write()方法传输时,文件position会自动更新。
//MappedByteBuffer类使得我们可以通过ByteBufferAPI来访问数据文件
byteBuffer(fcin,fcout);//2秒
mapByteBuffer(fcin,fcout);//1秒
}
//创建缓冲区
publicstaticvoidbyteBuffer(FileChannelfcin,FileChannelfcout)throwsIOException{
ByteBufferbuffer=ByteBuffer.allocate(1024);
//MappedByteBuffermapBuffer=fcin.map(FileChannel.MapMode.READ_ONLY,0,fcin.size());
Datestart=newDate();
while(true){
//clear方法重设缓冲区,使它可以接受读入的数据
buffer.clear();
//从输入通道中将数据读到缓冲区
intr=fcin.read(buffer);
//read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1
if(r==-1){
break;
}
//flip方法让缓冲区可以将新读入的数据写入另一个通道
buffer.flip();
//将缓冲区内容写入输出通道
fcout.write(buffer);
}
Dateend=newDate();
System.out.println("150MbyteBufferspend:
"+(end.getTime()-start.getTime())/1000+"sec");//150M4秒
}
//创建映射缓冲区,把文件的内容被映像到计算机虚拟内存的一块区域,
//这样就可以直接操作内存当中的数据而无需操作的时候每次都通过I/O去物理硬盘读取文件
publicstaticvoidmapByteBuffer(FileChannelfcin,FileChannelfcout)throwsIOException{
MappedByteBuffermapBuffer=fcin.map(FileChannel.MapMode.READ_ONLY,0,fcin.size());
Datestart=newDate();
fcout.write(mapBuffer);//将映射缓冲区直接写入输出通道
Dateend=newDate();
System.out.println("150MmapByteBufferspend:
"+(end.getTime()-start.getTime())/1000+"sec");//150M4秒
}
}
(二)异步IO:
●传统IO:
服务端:
publicclassSynchServerSocket{
privateintport=8821;
privateServerSocketserverSocket;
privateExecutorServiceexecutorService;//线程池
privatefinalintPOOL_SIZE=10;//单个CPU线程池大小
publicSynchServerSocket()throwsIOException{
serverSocket=newServerSocket(port);
//Runtime的availableProcessor()方法返回当前系统的CPU数目.
executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);
System.out.println("服务器启动");
}
publicvoidservice(){
while(true){
Socketsocket=null;
try{
//接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接,
//如果客户端未连接,服务端一直阻塞I/O等待连接,多线程从而耗费CPU及栈资源
socket=serverSocket.accept();
executorService.execute(newHandler(socket));
}catch(Exceptione){
e.printStackTrace();
}
}
}
publicstaticvoidmain(String[]args)throwsIOException{
newSynchServerSocket().service();//服务启动一直等待连接
}
}
classHandlerimplementsRunnable{
privateSocketsocket;
publicHandler(Socketsocket){
this.socket=socket;
}
privatePrintWritergetWriter(Socketsocket)throwsIOException{//根据socket获取输出流
OutputStreamsocketOut=socket.getOutputStream();
returnnewPrintWriter(socketOut,true);
}
privateBufferedReadergetReader(Socketsocket)throwsIOException{//根据socket获取输入流
InputStreamsocketIn=socket.getInputStream();
returnnewBufferedReader(newInputStreamReader(socketIn));
}
publicStringecho(Stringmsg){
return"echo:
"+msg;
}
publicvoidrun(){
try{
System.out.println("Newconnectionaccepted"+socket.getInetAddress()+":
"+socket.getPort());
BufferedReaderbr=getReader(socket);
PrintWriterpw=getWriter(socket);
Stringmsg=null;
while((msg=br.readLine())!
=null){
System.out.println(msg);
pw.println(echo(msg));
if(msg.equals("bye"))
break;
}
}catch(IOExceptione){
e.printStackTrace();
}finally{
try{
if(socket!
=null)
socket.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
客户端:
publicclassSynchClientSocket{
publicstaticvoidmain(String[]args){
intnumTasks=10;
ExecutorServiceexec=Executors.newCachedThreadPool();
for(inti=0;i exec.execute(newTask(i)); } } } classTaskimplementsRunnable{ privateSocketsocket=null; privateintport=8821; publicfinalinttaskId=0; privateinttaskID; publicTask(inttaskID){ this.taskID=taskID; } @Override publicvoidrun(){ System.out.println("Task"+taskID+": start"); try{ socket=newSocket("localhost",port); //发送关闭命令 OutputStreamsocketOut=socket.getOutputStream(); socketOut.write("shutdown\r\n".getBytes()); //接收服务器的反馈 BufferedReaderbr=newBufferedReader(newInputStreamReader(socket.getInputStream())); Stringmsg=null; while((msg=br.readLine())! =null) System.out.println("response: "+msg); }catch(IOExceptione){ e.printStackTrace(); } } } ●异步IO(多路复用,通知模式) 服务端: publicclassAsynServerimplementsRunnable{ privateByteBufferr_buff=ByteBuffer.allocate(1024); privateByteBufferw_buff=ByteBuffer.allocate(1024); privatestaticintport=8848; publicAsynServer(){ newThread(this).start(); } @Override publicvoidrun(){ try{ //多路复用: Selector各种IO事件注册到Selector,事件发生通知,不同通道对象注册到Selector Selectorselector=Selector.open(); //生成一个服务端口通道ssc ServerSocketChannelssc=ServerSocketChannel.open(); //将侦听端设为异步方式 ssc.configureBlocking(false); //将服务端口通道ssc绑定一个端口 ssc.socket().bind(newInetSocketAddress(port)); //将服务端口通道注册到selector上监听事件为OP_ACCEPT信号 ssc.register(selector,SelectionKey.OP_ACCEPT); System.out.println("echoserverhasbeensetup......"); while(true){ intn=selector.select(); if(n==0){//没有指定的I/O事件发生(监听是否有数据读或写)n>0,才会有selectedKeys continue; } //当有读或写等任何注册的事件发生时,可以从Selector中获得相应的SelectionKey,同时从SelectionKey //中可以找到发生的事件和该事件所发生的具体的SocketChannle继承自SelectableChannel,以获得客户端发送过来的数据。 Iteratorit=selector.selectedKeys().iterator(); while(it.hasNext()){ SelectionKeykey=(SelectionKey)it.next(); if(key.isAcceptable()){//侦听端信号触发 ServerSocketChannelserver=(ServerSocketChannel)key.channel(); //接受一个新的连接 SocketChannelsc=server.accept(); sc.configureBlocking(false); //设置该socket的异步信号OP_READ: 当socket可读时, //触发函数DealwithData(); sc.register(selector,SelectionKey.OP_READ); }else{ if(key.isReadable()){//某socket可读信号 DealwithData(key); } it.remove(); } //删除处理过的选择键 it.remove(); } } }catch(Exceptione){ } } publicvoidDealwithData(SelectionKeykey)throwsIOException{ intcount; //由key获取指定socketchannel的引用 SocketChannelsc=(SocketChannel)key.channel(); r_buff.clear(); //读取数据到r_buff while((count=sc.read(r_buff))>0); //确保r_buff可读 r_buff.flip(); //清空写缓存 w_buff.clear(); //将r_buff内容拷入w_buff w_buff.put(r_buff); w_buff.flip();//从写缓冲区向输出通道写之前调用flip EchoToClient(sc); w_buff.clear(); r_buff.clear(); } publicvoidEchoToClient(SocketChannelsc)throwsIOException{ while(w_buff.hasRemaining()) sc.write(w_buff); } publicstaticvoidmain(Stringargs[]){ if(args.length>0){ port=Integer.parseInt(args[0]); } newAsynServer(); } } 客户端: publicclassAsynClient{ privateSocketChannelsc; privatefinalintMAX_LENGTH=1024; privateByteBufferr_buff=ByteBuffer.allocate(MAX_LENGTH); privateByteBufferw_buff=ByteBuffer.allocate(MAX_LENGTH); privatestaticStringhost; privatestaticintport=8848; publicAsynClient(){ try{ InetSocketAddressaddr=newInetSocketAddress(host,port); //生成一个socketchannel sc=SocketChannel.open(); //连接到server sc.connect(addr); while(! sc.finishConnect()) ; System.out.println("connectionhasbeenestablished! ..."); while(true){ //回射消息 Stringecho; try{ System.err.println("Entermsgyou'dliketosend: "); BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in)); //输入回射消息 echo=br.readLine(); //把回射消息放入w_buff中 w_buff.clear(); w_buff.put(echo.getBytes()); w_buff.flip(); }catch(IOExceptionioe){ System.err.println("sth.iswrongwithbr.readline()"); } //发送消息 while(w_buff.hasRemaining()) sc.write(w_buff); w_buff.clear(); //进入接收状态 Rec(); //间隔1秒 Thread.currentThread().sleep(1000); } }catch(IOExceptionioe){ ioe.printStackTrace(); } catch(InterruptedExceptionie){ ie.printStackTrace(); } } publicvoidRec()
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java NIO总结 NIO 总结