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

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

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

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

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

您似乎正在使用InputStream,并且根据InputStream.read()的JDK文档 ,读取块完全如您所述 – 在收到数据之前,到达文件结尾,或者抛出exception。

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

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

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

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

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