NIO学习笔记——解决“服务器端cpu占用率高”

原文地址:http://blog.csdn.net/hepeng19861212/article/details/4479714


问题:服务器端启动后,cpu占用率很高,经常是99%,100%。
原因分析:RecvThread的终止判断条件最初是if (num == -1)//这里的num是指通道读取到buffer中的字节数,当没有数据时,客户端的IntputStream始终没有终止或关闭,
也就是说SocketChannel始终无法读到流的末尾。但是服务器的channel始终在尝试读取客户端的数据,但读取的数据都为空,
这样就使得cpu一直在做“无用功”——空转。

--------------------------------------------------
或许你会问,只不过才一个线程在接收数据而已,不至于使得cpu慢的如老牛耕地吧?你这样说是没错的。但是接下来,我在无意中做了个
小小的实验:我在RecvThread类中加入了运行时的debug信息。
另外,请观众注意,当我们在ListenThread中启动RecvThread并运行的同时,原先的线程ListenThread也没闲着,而是在继续往下执行。

服务器端启动后,我使用客户端发送了一个字符(仅仅是一个字符)给服务器端,意外出现了:服务器的console中打印了不止一个RecvThread线程的debug信息。
为什么会有这么多线程?按照我们的思路,当判断SelectionKey是readable厚,我们只new了一个线程来接收数据啊。而且NIO api中对

Selector的select()方法解释如下:

[java] view plaincopy

public abstract int select()
throws IOException
选择一组键,其相应的通道已为 I/O 操作准备就绪。
此方法执行处于阻塞模式的选择操作。仅在至少选择一个通道、调用此选择器的 wakeup 方法,或者当前的线程已中断(以先到者为准)后此方法才返回。

是啊,没错啊,只有select至少一个有效的通道时,select()才会返回,否则就一直阻塞。
但是,从我刚才的实验中,大家也许很清楚的看到了,其实当RecvThread处理数据的同时,select()方法并没有阻塞,继而它后面的程序仍然会继续执行。
以至于new 了第二个、第三个....第n个RecvThread的实例。
后来我专门又输出了select()的返回值,结果也进一步验证了我刚才所言——RecvThread线程处理数据的同时,select()并没有老老实实的阻塞在那里,而是返回了一个0。

最后,唯一令我感到欣慰的是,这n个线程并不是每一个都接收了客户端发来的数据,而是仅仅其中一个线程接收到了数据。



解决方法:把RecvThread的终止判断条件改成if (num <= 0),并且强烈建议您:不要在selectionKey.isReadable()判断之后,去新建一个线程来接收到来的数据。原因1是因为刚才我所讲的一个消息对应n个线程,将耗费掉大量的cpu资源,
而且这n个线程中为我们做事的却只有其中一个(这也许刚好就是当今经济危机下大部分企业都在裁员的原因)。原因之二,千万不要单纯以为这不过是n个线程而已,
服务器接收客户端消息是很频繁的,一个消息对应n个线程,那么100条消息就对应了.....我想你不会希望看到自己的cpu被这n*100个线程累垮。^_^
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值