Java线程不会在I / O操作上暂停

时间:2009-11-23 17:09:05

标签: java networking multithreading udp blocking

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

3 个答案:

答案 0 :(得分: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?

答案 1 :(得分:0)

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

答案 2 :(得分:-1)

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