2

我的印象是,在 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 版本中工作。

4

3 回答 3

1

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

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

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

更新:进一步看,似乎DatagramSocket.receive 方法是同步的。因此,解释您所看到的行为的方法是,您正在启动两个尝试使用同一个 DatagramSocket 实例的线程——如果两个线程试图在同一个 DatagramSocket 实例上执行 receive(),一个会阻塞实例,直到它完成,另一个将被阻止。(Sun 论坛上也有一篇文章对此进行了描述。)这可能是正在发生的事情——您正在为两个线程重用相同的 DatagramSocket?

于 2009-11-23T17:32:41.077 回答
0

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

于 2011-12-28T04:52:06.517 回答
-1

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

于 2009-11-23T20:52:44.713 回答