您好,我是湘王,这是我的博客园 , 欢迎您来,欢迎您再来~
在Java NIO的三大核心中 , 除了Channel和Buffer , 剩下的就是Selector了 。有的地方叫它选择器,也有叫多路复用器的(比如Netty) 。
之前提过,数据总是从Channel读取到Buffer , 或者从Buffer写入到Channel , 单个线程可以监听多个Channel——Selector就是这个线程背后的实现机制(所以得名Selector) 。
![4 Java I/O:AIO和NIO中的Selector](http://img.zhejianglong.com/231018/1PR64256-0.jpg)
文章插图
Selector通过控制单个线程处理多个Channel,如果应用打开了多个Channel,但每次传输的流量都很低,使用Selector就会很方便(至于为什么 , 具体到Netty中再分析) 。所以使用Selector的好处就显而易见:用最少的资源实现最多的操作 , 避免了线程切换带来的开销 。
还是以代码为例来演示Selector的作用 。新建一个类 , 在main()方法中输入下面的代码:
/** * NIO中的Selector * * @author xiangwang */public class TestSelector {public static void main(String args[]) throws IOException {// 创建ServerSocketChannelServerSocketChannel channel1 = ServerSocketChannel.open();channel1.socket().bind(new InetSocketAddress("127.0.0.1", 8080));channel1.configureBlocking(false);ServerSocketChannel channel2 = ServerSocketChannel.open();channel2.socket().bind(new InetSocketAddress("127.0.0.1", 9090));channel2.configureBlocking(false);// 创建一个Selector对象Selector selector = Selector.open();// 按照字面意思理解,应该是这样的:selector.register(channel, event);// 但其实是这样的:channel.register(selector, SelectionKey.OP_READ);// 四种监听事件:// OP_CONNECT(连接就绪)// OP_ACCEPT(接收就绪)// OP_READ(读就绪)// OP_WRITE(写就绪)// 注册Channel到Selector,事件一旦被触发,监听随之结束SelectionKey key1 = channel1.register(selector, SelectionKey.OP_ACCEPT);SelectionKey key2 = channel2.register(selector, SelectionKey.OP_ACCEPT);// 模板代码:在编写程序时,大多数时间都是在模板代码中添加相应的业务代码while(true) {int readyNum = selector.select();if (readyNum == 0) {continue;}Set<SelectionKey> selectedKeys = selector.selectedKeys();// 轮询for (SelectionKey key : selectedKeys) {Channel channel = key.channel();if (key.isConnectable()) {if (channel == channel1) {System.out.println("channel1连接就绪");} else {System.out.println("channel2连接就绪");}} else if (key.isAcceptable()) {if (channel == channel1) {System.out.println("channel1接收就绪");} else {System.out.println("channel2接收就绪");}}// 触发后删除,这里不删// it.remove();}}}}代码写好后启动ServerSocketChannel服务,可以看到我这里已经启动成功:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/163193/14/31572/21350/635201eeEf867f75c/1bb497da5749c617.png)
文章插图
然后在网上下载一个叫做SocketTest.jar的工具(在一些工具网站下载的时候当心中毒,如果不放心,可以私信我,给你地址),双击打开,并按下图方式执行:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/118373/25/30830/45810/635201eeEf8c6865d/816709cf23d725e8.png)
文章插图
点击「Connect」可以看到变化:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/193467/10/29509/23118/635201efE13982a7b/ffa15417ad4fa171.png)
文章插图
然后点击「Disconnect」,再输入「9090」后,再点击「Connect」试试:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/132002/18/29573/45927/635201efE8f5ea4eb/a17875fef969217f.png)
文章插图
可以看到结果显示结果变了:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/207586/12/26376/25482/635201f0E6677542c/e51d1e56963b68d3.png)
文章插图
两次连接,打印了三条信息:说明selector的轮询在起作用(因为Set<SelectionKey>中包含了所有处于监听的SelectionKey) 。但是「接收就绪」监听事件仅执行了一次就再不响应 。如果感兴趣的话你可以把OP_READ、OP_WRITE这些事件也执行一下试试看 。
因为Selector是单线程轮询监听多个Channel,那么如果Selector(线程)之间需要传递数据,怎么办呢?——Pipe登场了 。Pipe就是一种用于Selector之间数据传递的「管道」 。
先来看个图:
![4 Java I/O:AIO和NIO中的Selector](https://m.360buyimg.com/jdcms/jfs/t1/44102/10/20585/27822/635201f0Eb2fd4be5/d42f67c485834437.png)
文章插图
可以清楚地看到它的工作方式 。
【4 Java I/O:AIO和NIO中的Selector】还是用代码来解释 。
/** * NIO中的Pipe * * @author xiangwang */public class TestPipe {public static void main(String args[]) throws IOException {// 打开管道Pipe pipe = Pipe.open();// 将Buffer数据写入到管道Pipe.SinkChannel sinkChannel = pipe.sink();ByteBuffer buffer = ByteBuffer.allocate(32);buffer.put("ByteBuffer".getBytes());// 切换到写模式buffer.flip();sinkChannel.write(buffer);// 从管道读取数据Pipe.SourceChannel sourceChannel = pipe.source();buffer = ByteBuffer.allocate(32);sourceChannel.read(buffer);System.out.println(new String(buffer.array()));// 关闭管道sinkChannel.close();sourceChannel.close();}}
推荐阅读
- redmi k40和k40pro区别_手机参数对比
- 天玑920和天玑1000+性能对比_哪款性能更好
- 小米12和荣耀magic3哪个好-小米12和荣耀magic3参数对比
- iphone13pro和华为p50pro拍照对比_哪款拍照效果更好
- 荣耀平板v7pro和小米平板5哪个好_荣耀平板v7pro和小米平板5对比
- vivos9和s10差别大吗_s9有必要换s10吗
- 天玑1200和天玑1000+的区别_天玑1200和天玑1000+有什么区别
- Vue3 SFC 和 TSX 方式调用子组件中的函数
- 10 微服务架构学习与思考:微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍
- 苹果iphone13mini和12mini有什么区别_参数对比