java.nio异步线程安全的IO

BIO 方式使得整个处理过程和连接是绑定的,只要连接建立,无论客户端是否有消息发送,都要进行等待处理,一定程度上浪费了服务器端的硬件资源,因此就有了 NIO 方式。Java 对于 NIO 方式的支持是通过 Channel和 Selector 方式来实现,采用的方法为向 Channel注册感兴趣的事件,然后通过 Selector 来获取到发生了事件的 key,如发生了相应的事件,则进行相应的处理,否则则不做任何处理,是典型的Reactor 模式,按照这样的方式,就不用像 BIO 方式一样,即使在没有消息的情况下也需要占据一个线程来阻塞读取消息,从而提升服务器的使用效率, 为实现 TCP/IP+NIO 方式的系统间通讯, Java 提供了 SocketChannel和 ServerSocketChannel两个关键的类,网络 IO 的操作则改为通过ByteBuffer 来实现,具体的基于 java实现TCP/IP+NIO 方式的通讯的方法如下所示。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

package com.flyoung;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.util.Iterator;

import java.util.Set;

import java.nio.channels.SocketChannel;

public class NIOServer {

    /*标志数字*/

    private static int flag = 0;

    /*定义缓冲区大小*/

    private static int block = 4096;

    /*接收缓冲区*/

    private static ByteBuffer receiveBuffer = ByteBuffer.allocate(block);

    /*发送缓冲区*/

    private static ByteBuffer sendBuffer = ByteBuffer.allocate(block);

    /*定义Selector*/

    private Selector selector;

    

    public NIOServer(int port) throws IOException{

        //打开服务器套接字通道

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //服务器配置为非阻塞

        serverSocketChannel.configureBlocking(false);

        //检索与此服务器套接字通道关联的套接字

        ServerSocket serverSocket = serverSocketChannel.socket();

        //进行服务的绑定

        serverSocket.bind(new InetSocketAddress(port));

        //通过open()方法找到Selector

        selector = Selector.open();

        //注册到selector

        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server Start -----8888:");

    }

    //监听

    public void listen() throws IOException{

        while(true){

            //监控所有注册的 channel ,当其中有注册的 IO 操作可以进行时,该函数返回,并将对应的 SelectionKey 加入 selected-key set

            selector.select();

            //Selected-key set 代表了所有通过 select() 方法监测到可以进行 IO 操作的 channel ,这个集合可以通过 selectedKeys() 拿到

            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while(iterator.hasNext()){

                SelectionKey selectionKey = iterator.next();

                handleKey(selectionKey);

                iterator.remove();

            }

        }

        

    }

    //处理请求

    public void handleKey(SelectionKey selectionKey) throws IOException{

        //接受请求

        ServerSocketChannel serverSocketChannel = null;

        SocketChannel socketChannel = null;

        String receiveText;

        String sendText;

        int count;

        //测试此键的通道是否准备好接受新的套接字连接

        if(selectionKey.isAcceptable()){

            //返回创建此键的通道

            serverSocketChannel = (ServerSocketChannel)selectionKey.channel();

            //接受客户端建立连接的请求,并返回 SocketChannel 对象

            socketChannel = serverSocketChannel.accept();

            //配置为非阻塞

            socketChannel.configureBlocking(false);

            //注册到selector

            socketChannel.register(selector, SelectionKey.OP_READ);

        }else if(selectionKey.isReadable()){

            //返回为之创建此键的通道

            socketChannel = (SocketChannel)selectionKey.channel();

            //将缓冲区清空,以备下次读取

            receiveBuffer.clear();

            //将发送来的数据读取到缓冲区

            

            count = socketChannel.read(receiveBuffer);

        

            

            if(count>0){

                receiveText = new String(receiveBuffer.array(),0,count);

                System.out.println("服务器端接受到的数据---"+receiveText);

                socketChannel.register(selector, SelectionKey.OP_WRITE);

            }

        }else if (selectionKey.isWritable()) {  

            //将缓冲区清空以备下次写入  

            sendBuffer.clear();  

            // 返回为之创建此键的通道。  

            socketChannel = (SocketChannel) selectionKey.channel();  

            sendText="message from server--" + flag++;  

            //向缓冲区中输入数据  

            sendBuffer.put(sendText.getBytes());  

             //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位  

            sendBuffer.flip();  

            //输出到通道  

            socketChannel.write(sendBuffer);  

            System.out.println("服务器端向客户端发送数据--:"+sendText);  

            socketChannel.register(selector, SelectionKey.OP_READ);  

        }  

        

    }

    public static void main(String[] args) throws IOException {

        int port = 8888

        NIOServer server = new NIOServer(port);

        server.listen();

    }

}

时间: 2024-10-06 20:41:45

java.nio异步线程安全的IO的相关文章

从底层入手,图解 Java NIO BIO MIO AIO 四大IO模型与原理

目录 写在前面 1.1. Java IO读写原理 1.1.1. 内核缓冲与进程缓冲区 1.1.2. java IO读写的底层流程 1.2. 四种主要的IO模型 1.3. 同步阻塞IO(Blocking IO) 1.4. 同步非阻塞NIO(None Blocking IO) 1.5. IO多路复用模型(I/O multiplexing) 1.6. 异步IO模型(asynchronous IO) 小结一下: 写在最后 疯狂创客圈 百万级流量 高并发实战 疯狂创客圈 Java 分布式聊天室[ 亿级流量

JAVA NIO ServerSocketChannel(线程池版)

服务器端: import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSock

JAVA NIO Scatter/Gather(矢量IO)

矢量IO=Scatter/Gather: 在多个缓冲区上实现一个简单的IO操作.减少或避免了缓冲区拷贝和系统调用(IO) write:Gather 数据从几个缓冲区顺序抽取并沿着通道发送,就好比全部缓冲区全部连接起来放入一个大的缓冲区进行发送,缓冲区本身不具备gather能力. read:Scatter 从通道读取的数据会按顺序散布到多个缓冲区,直到缓冲区被填满或者通道数据读完. Gather: Scatter: 示例代码: 1 /** 2 * channel Gather/Scatter 3

Java基础:非阻塞式IO

转载请注明出处:jiq?钦's technical Blog 引言 JDK1.4中引入了NIO,即New IO,目的在于提高IO速度.特别注意JavaNIO不完全是非阻塞式IO(No-Blocking IO),因为其中部分通道(如FileChannel)只能运行在阻塞模式下,而其他的通道可以在阻塞式和非阻塞式之间进行选择. 尽管这样,我们还是习惯将Java NIO看作是非阻塞式IO,而前面介绍的面向流(字节/字符)的IO类库则是非阻塞的,详细来看,两者区别如下: IO NIO 面向流(Strea

Java NIO 系列教程(转)

原文中说了最重要的3个概念,Channel 通道Buffer 缓冲区Selector 选择器其中Channel对应以前的流,Buffer不是什么新东西,Selector是因为nio可以使用异步的非堵塞模式才加入的东西.以前的流总是堵塞的,一个线程只要对它进行操作,其它操作就会被堵塞,也就相当于水管没有阀门,你伸手接水的时候,不管水到了没有,你就都只能耗在接水(流)上.nio的Channel的加入,相当于增加了水龙头(有阀门),虽然一个时刻也只能接一个水管的水,但依赖轮换策略,在水量不大的时候,各

Java NIO 系列教程

转载于http://www.iteye.com/magazines/132-Java-NIO Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO.感谢并发编程网的翻译和投递. (关注ITeye官微,随时随地查看最新开发资讯.技术文章.) Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流

转:Java NIO

Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO.感谢并发编程网的翻译和投递. (关注ITeye官微,随时随地查看最新开发资讯.技术文章.) Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通

Java NIO 完全学习笔记(转)

本篇博客依照 Java NIO Tutorial翻译,算是学习 Java NIO 的一个读书笔记.建议大家可以去阅读原文,相信你肯定会受益良多. 1. Java NIO Tutorial Java NIO,被称为新 IO(New IO),是 Java 1.4 引入的,用来替代 IO API的. Java NIO:Channels and Buffers 标准的 Java IO API ,你操作的对象是字节流(byte stream)或者字符流(character stream),而 NIO,你操

java NIO-Channel

基本简介 Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中. Java NIO: Non-blocking IO(非阻塞IO) Java