【问题标题】:Java Thread won't pause on I/O operationJava 线程不会在 I/O 操作上暂停
【发布时间】:2009-11-23 17:09:05
【问题描述】:

我的印象是,在 Java 中,线程会在阻塞 I/O 操作(如 Socket.read() 或 DataGramsocket.receive() )期间暂停并让其他线程有机会做一些工作。由于某种原因,在我的多线程网络应用程序中,对 receive() 的调用导致我所有其他线程都饿死了(调用 receive() 的线程正在成为大老板并且永不放弃控制,因此永远阻塞!)

为什么会发生这种情况?我曾经有同样的应用程序,但不是 UDP,而是基于 TCP 的。 Socket.read() 总是暂停线程并允许其他人工作一段时间,如果它阻塞太久。

-- 额外信息-- 我的自定义线程的 TCP 版本是这样的代码: http://www.dwgold.com/code/proxy/proxyThread.java.txt

我的新代码(UDP 版本)几乎相同,但稍作修改以使用 UDP 方法和样式。然后我创建了其中两个线程并在两个线程上调用 start。第一个线程总是阻塞并且永远不会让另一个线程在 UDP 版本中工作。

【问题讨论】:

  • 我找不到任何对 Socket.read() 方法的引用;你能指出它来自哪个包裹吗?
  • read() 在 InputStream 上定义。我想这是帖子中的错字,但我还没有找到 receive(),这既不是 InputStream 上的方法,也不是 Socket 上的方法
  • gotcha - receive() 是在 DatagramChannel 上定义的方法 :)
  • 如果您从控制台运行此应用程序,请在控制台上获取线程转储。这将准确地向您展示您的线程在挨饿时正在做什么......这可能不是我们最初假设的那样。

标签: java networking multithreading udp blocking


【解决方案1】:

您似乎正在使用 InputStream,并且根据the JDK docs for InputStream.read(),读取块与您描述的完全一样——直到接收到数据、到达文件结尾或出现异常扔了。

所以对我来说,问题是:为什么你的代码的 TCP 版本允许块被中断?这似乎没有任何意义。也许您的 TCP 代码将读取分解为离散的、足够短的突发,以便线程有机会在对 read() 的单独调用之间跳转?

进一步看,我发现不同之处在于您的代码的 TCP 版本通过 Socket 提供的 InputStream 接收数据,而您的代码的 UDP 版本直接从 DatagramSocket 自己的 receive() 方法接收数据。所以我认为这只是两者(InputStream.read 和 DatagramSocket.receive)提供的功能之间的根本区别。您是否考虑过使用DatagramPacket.setSoTimeout 在套接字的接收块上设置超时,然后在超时的receive() 调用抛出 SocketTimeoutException 时捕获它?你应该能够实现它来实现你想要的。

更新:再往前看,似乎是the DatagramSocket.receive method is synchronized。因此,解释您所看到的行为的方法是,您正在启动两个尝试使用同一个 DatagramSocket 实例的线程——如果两个线程试图在同一个 DatagramSocket 实例上执行 receive(),一个线程将阻塞实例直到它完成,另一个将被阻止。 (还有a post on the Sun forums that describes this。)这可能是正在发生的事情——你为两个线程重用了相同的DatagramSocket?

【讨论】:

  • 不,InputStream.read当然不会阻塞其他线程,只会阻塞当前线程。
  • 啊,我想我当时看错了——我以为这一切都发生在同一个线程中。
【解决方案2】:

这可能是因为 Java 线程是用户级线程(与内核级线程相反)。 一个内核级线程可以包含多个用户级线程。但是,如果一个用户级线程等待 io,内核无法仅将该用户级线程放在等待队列中,它只能将整个内核线程放在等待队列中(用户级线程在用户级调度,不在内核级别)。因此,等待 io 的单个用户级线程可以/将阻塞所有其他用户级线程(来自该内核线程)。

【讨论】:

    【解决方案3】:

    对于您所描述的行为,实际上没有任何解释,即从 Socket 读取 InputStream 会导致“所有其他线程”暂停。您是否有机会启动多个线程,这些线程都从同一个套接字读取,而您的实际意思是所有 这些 线程都挂起?在这种情况下,我希望从套接字读取的数据在线程之间任意划分。

    【讨论】:

    • 请记住,他所描述的行为不是发生在 InputStream 上,而是发生在 DatagramSocket 上——问题行为中不涉及 InputStream,仅在功能行为中(他的代码的 TCP 版本) )。
    猜你喜欢
    • 2018-08-04
    • 2012-09-01
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    • 2018-11-04
    相关资源
    最近更新 更多