Java非阻塞IO选择器导致通道寄存器阻塞

2023-12-06

我有两个线程正在处理非阻塞套接字的 Java NIO。这就是线程正在做的事情:

主题 1: 调用选择器的 select() 方法的循环。如果有可用的密钥,则会对它们进行相应的处理。

话题2: 偶尔会通过调用 register() 将 SocketChannel 注册到选择器。

问题是,除非 select() 的超时时间非常小(比如 100 毫秒左右),否则对 register() 的调用将无限期地阻塞。即使通道配置为非阻塞,并且 javadoc 声明 Selector 对象是线程安全的(但我知道它的选择键不是)。

那么有人对问题可能是什么有任何想法吗?如果我将所有内容都放在一个线程中,该应用程序将完美运行。然后就不会出现问题了,但我真的很想有单独的线程。任何帮助表示赞赏。我在下面发布了我的示例代码:

将 select(1000) 更改为 select(100) 即可。将其保留为 select() 或 select(1000) ,但它不会。


import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

公共类 UDPSocket { 私有 DatagramChannel 客户端通道; 私有字符串 dstHost; 私有 int dstPort; 私有静态选择器recvSelector; 私有静态易失性布尔值已初始化; 私有静态ExecutorService eventQueue = Executors.newSingleThreadExecutor();

公共静态无效初始化() { 初始化=真;

尝试 { recvSelector = Selector.open(); } 捕获(IOException e) { System.err.println(e); }

线程 t = 新线程(新 Runnable() { @覆盖 公共无效运行() { 同时(初始化) { 读取数据(); Thread.yield(); } }
}); t.start(); }

公共静态无效关闭() { 初始化=假; }

私有静态无效readData() { 尝试 { int numKeys = recvSelector.select(1000);

if (numKeys > 0) { 迭代器 i = recvSelector.selectedKeys().iterator();

while(i.hasNext())
{
 SelectionKey key = i.next();
 i.remove();

 if (key.isValid() && key.isReadable())
 {
  DatagramChannel channel = (DatagramChannel) key.channel();

  // allocate every time we receive so that it's a copy that won't get erased
  final ByteBuffer buffer = ByteBuffer.allocate(Short.MAX_VALUE);
  channel.receive(buffer);
  buffer.flip();
  final SocketSubscriber subscriber = (SocketSubscriber) key.attachment();

  // let user handle event on a dedicated thread
  eventQueue.execute(new Runnable()
  {
   @Override
   public void run() 
   {
    subscriber.onData(buffer);
   }       
  });
 }
}

} } 捕获(IOException e) { System.err.println(e); }
}

公共 UDPSocket(字符串 dstHost, int dstPort) { 尝试 { this.dstHost = dstHost; this.dstPort = dstPort; clientChannel = DatagramChannel.open(); clientChannel.configureBlocking(假); } 捕获(IOException e) { System.err.println(e); } }

公共无效addListener(SocketSubscriber订阅者) { 尝试 { DatagramChannel serverChannel = DatagramChannel.open(); serverChannel.configureBlocking(假); DatagramSocket套接字 = serverChannel.socket(); socket.bind(new InetSocketAddress(dstPort)); SelectionKey key = serverChannel.register(recvSelector, SelectionKey.OP_READ); key.attach(订阅者); } 捕获(IOException e) { System.err.println(e); } }

公共无效发送(ByteBuffer缓冲区) { 尝试 { clientChannel.send(buffer, new InetSocketAddress(dstHost, dstPort)); } 捕获(IOException e) { System.err.println(e); } }

公共无效关闭() { 尝试 { clientChannel.close(); } 捕获(IOException e) { System.err.println(e); } } }


选择器有多个已记录的内部同步级别,您正在遇到所有这些级别。称呼wakeup()在调用之前在选择器上register().确保select()如果选择的键为零,循环将正常工作,这将发生在wakeup().

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java非阻塞IO选择器导致通道寄存器阻塞 的相关文章

随机推荐

  • 如何合并两个文件?

    我有两个文件 File 1 7118 7457 7591 7539 8001 File 2 5003 5008 5011 5026 5028 5029 5031 我需要的输出 7118 5003 7457 5003 7591 5003 75
  • Scala 中的右关联方法有什么好处?

    我刚刚开始使用 Scala 并且刚刚了解了如何创建方法右结合 与更传统的左结合性在命令式面向对象语言中很常见 起初 当我看到示例代码时consScala 中的列表 我注意到每个示例总是在右侧有列表 println 1 List 2 3 4
  • Elasticsearch - 从 6.7 升级到 7.0 后,此搜索不会返回正确的结果

    query constant score filter bool should terms field a value1 value2 must term field b value
  • JPEG编码器速度超慢,如何优化?

    我正在 Flash 构建器中使用 actionscript 3 0 构建一个应用程序 这是一个后续问题这个问题 我需要将字节数组上传到我的服务器 但是我使用的函数将位图数据转换为ByteArray速度超级慢 慢到我的移动设备都卡住了 我的代
  • Sencha Touch 复选框字段具有带有长标签的时髦布局

    我的应用程序中的几个复选框字段有很长的标签 不幸的是它会导致一些奇怪的行为 有什么办法可以让这个看起来好一点吗 我的意思是 如果我 触摸 灰色区域 复选框不会激活 即使复选框位于灰色区域内 但我必须单击白色区域 这有点令人困惑 即使我设定l
  • 如何在 Oracle 查询中禁用 PL/SQL

    以下是我希望阻止在我的服务器上运行的查询类型的示例 begin While True LOOP dbms output put line tst END LOOP end 此查询 或其他类似查询 可能通过 Oracle JDBC 瘦驱动程序
  • Swift - 更新/刷新显示时间的标签

    我有一个以 12 小时格式显示当前时间的标签 但是 它不会在每次分钟 小时更改时更新 刷新时间 我需要它在时间改变时自动将标签更改为当前时间 斯威夫特 3 解决方案 class ViewController IBOutlet weak va
  • onfocus时如何更改文本框的背景颜色?

    我尝试了这段代码 但它不起作用 当我聚焦文本框时 它显示错误 function ChangeBgColor obj evt if evt type focus style background lightgrey else if evt t
  • bxslider 上 z 索引元素的顺序

    我需要使用无子元素来订购 bxslider 的内容 图像和顶部文本之间 e g div ul li img src image1 jpg span text span li ul div class under text over imag
  • Facebook ShareDialog 中未显示说明

    我正在 Android 应用程序中使用 Facebook 的 ShareDialog 尝试 ShareLinkContent 以下是我使用过的代码片段 我有帖子所需的内容标题和描述 当我尝试发布它时在手机中显示时很好 但是当我在 Faceb
  • 在Python 2.7中读取大型lz4压缩JSON数据集[关闭]

    Closed 这个问题是基于意见的 目前不接受答案 我需要分析作为 lz4 压缩 JSON 文件分发的大型数据集 压缩后的文件将近1TB 由于成本原因 我不想将其解压缩到磁盘 数据集中的每条 记录 都非常小 但将整个数据集读入内存显然是不可
  • 不使用 Azure 客户端 SDK 连接到 IoT 中心

    我想不使用客户端 SDK 连接到 Azure Iot Hub 在https azure microsoft com nb no blog upload files from devices with azure iot hub 有关于如何执
  • 如何添加到 Windows 中的 PYTHONPATH,以便它找到我的模块/包?

    我有一个目录 其中托管我的所有 Django 应用程序 C My Projects 我想将此目录添加到我的PYTHONPATH这样我就可以直接调用应用程序 我尝试添加C My Projects 到我的 WindowsPath来自 Windo
  • 将文档上传到 Google 云端硬盘时检测冲突

    我的 Android 应用程序更新了 Google 云端硬盘文档 该文件也可以在其他地方修改 例如通过云端硬盘网络界面 因此文件上传可能会发生冲突 然而 这种情况应该很少发生 这就是为什么我不希望我的应用程序首先查询修订历史记录 因为这在大
  • e.target 和 e.currentTarget 之间的区别

    我不明白其中的区别 它们看起来相同 但我想它们不是 何时使用其中之一的任何示例将不胜感激 e target是什么触发事件调度程序触发和e currentTarget是您为侦听器分配的内容
  • python代码中的Kivy ids

    main from kivy app import App from kivy uix button import Button from kivy uix screenmanager import ScreenManager Screen
  • 如何在客户端仍处于连接状态时更新 DataSnap 服务器?

    我们使用有状态的 DataSnap 服务器来执行某些业务逻辑任务 并提供客户端数据集数据 如果我们必须更新服务器来修改业务规则 我们将新版本复制到新的空文件夹中并注册它 取决于 Delphi 版本 只需启动或运行 TRegSvr 实用程序
  • 警告:函数的隐式声明

    我正在用 C 编程 我的 gcc 编译器在我的函数调用中给出以下警告mySedondFile c implicit declaration of function func 函数原型声明于myfile h as void func char
  • 使用 sysctl() 获取 osx 上的 cpu 信息

    我正在 osx 上工作 我想获得一些有关我的 cpu 的信息 为此 我找到了终端命令 sysctl a 但我需要在程序中获取这些信息 因此我需要使用函数 systcl 我试图阅读该男子 但我仍然不知道如何获取一个字符串 例如我的CPU的名称
  • Java非阻塞IO选择器导致通道寄存器阻塞

    我有两个线程正在处理非阻塞套接字的 Java NIO 这就是线程正在做的事情 主题 1 调用选择器的 select 方法的循环 如果有可用的密钥 则会对它们进行相应的处理 话题2 偶尔会通过调用 register 将 SocketChann