最近在和同学写一个Android端的类微信项目,不过非常简单,只有添加好友,设置备注,通话等功能。我主要负责服务器端的开发,在开发过程中,使用了Spring框架和Java NIO。有些东西,确实不写代码根本就学不会,在学习过程中,发现Java NIO中的一些易错点,特此记录,以备查询。(可能会不定时更新)

关闭断开的SocketChannel

当SelectionKey 可读时示例如下,前面代码省略

if(selectionKey.isReadable()) {
	SocketChannel clientChannel = ((SocketChannel)selectionKey.channel());
    ByteBuffer buffer = ByteBuffer.allocate(10);
    channel.read(buffer);
    byte[] date = buffer.array();
    String msg = new String(date).trim();
}

如果未检测 channel.read(buffer)的返回值,当客户端断开连接后,服务器端会不断的收到信息。修正如下。

if(selectionKey.isReadable()) {
	int size = 0;
    byte[] bytes = null;
	SocketChannel clientChannel = ((SocketChannel)selectionKey.channel());
    ByteArrayOutputStream byteArrayOutputStream  = new ByteArrayOutputStream();
    ByteBuffer buffer = ByteBuffer.allocate(10);
    while((size = clientChannel.read(buffer)) > 0) {
    	byteBuffer.flip();
        bytes = new byte[size];
        byteBuffer.get(bytes);
        byteArrayOutoutStream.write(bytes);
        byteBuffer.clear();
    }
    if(size == -1) {
    	socketChannel.close();
        byteBuffer.clear();
    }
    String msg = new String(bytes);
}

这样就不会出现SocketChannel一直可读的情况了。

ByteBuffer申请

先看一下是StackOverflow网站上有关的说明

You shouldn’t allocate your ByteBuffer once per read. Allocating ByteBuffers is an expensive operation. At least allocate it once per entry to the read method. Better still, allocate one per channel when you accept it. You can keep it as, or via, the key attachment so you don’t lose it, and so it disappears when you cancel the key or close the channel.

  • ByteBuffer有两种申请方式
ByteBuffer buffer = ByteBuffer.allocate(CAPACITY)
ByteBuffer direcateBuffer = ByteBuffer.allocate(CAPACITY) 

首先第一种是在JVM堆申请的内存中,由GC管理,第二种是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。

第一种JVM内存

很尴尬,无论是用英文还是中文都没有在网上找到任何有关ByteBuffer开销的说明,只有StackOverflow上的一句话。但是我觉得这句话一定不是空穴来风的。 细细想想好像还是有点道理的,必定每申请一次,都相当于C语言malloc一次,而且这种内存相当于朝生夕死的大内存,可能会分配在老生代中,这样申请多次的话,就会给GC带来极大的负担,建议放到类属性中。

关于第二种直接内存

由于直接内存是在OS Memory中,所以需要手动释放。尴尬的是,我并没有用过,就不扯淡了。 贴一下别人写的链接

今天才知道Java有两种NIO,普通NIO指的是在JDK1.4中引入的非阻塞NIO,而第二种NIO指的是AIO,学海无涯啊, 有机会再学。