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

发布于 2024-08-11 18:26:54 字数 593 浏览 8 评论 0原文

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

I was under the impression that in Java, a Thread will pause and give other threads a chance to do some work during blocking I/O operations ( like Socket.read() or DataGramsocket.receive() ). For some reason in my multi threaded network application, a call to receive() is causing all my other threads to starve ( the thread that called receive() is becoming a big boss and never giving up control, thus blocking forever! )

Why would this happen? I used to have the same exact application, but instead of UDP it was TCP based. Socket.read() always paused the Thread and allowed others to work for a bit if it blocked for too long.

-- extra info --
The TCP version of my custom thread was this code:
http://www.dwgold.com/code/proxy/proxyThread.java.txt

My new code ( UDP version ) is pretty much the same, but modified a bit to use UDP methods and style. I then created two of these threads and call start on both. The first thread always blocks and never lets the other do work in the UDP version.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

三人与歌 2024-08-18 18:26:54

看来您正在使用 InputStream,并且根据 InputStream.read()的 JDK 文档,读取块完全按照您的描述 - 直到收到数据,结束- 到达文件,或者抛出异常。

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

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

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

It seems that you're using an InputStream, and according to the JDK docs for InputStream.read(), the read blocks exactly as you've described -- until the data is received, an end-of-file is reached, or an exception is thrown.

So for me, the question is: why does the TCP version of your code allow the block to get interrupted? That doesn't seem to make any sense. Perhaps your TCP code breaks the reads up into discrete, short-enough bursts that the thread has a chance to jump in between separate calls to read()?

Looking further, I see that the difference is that the TCP version of your code receives data via the InputStream that's provided by Socket, whereas the UDP version of your code receives data directly from the DatagramSocket's own receive() method. So I'd posit that this is just a fundamental difference between the functionality offered by the two (InputStream.read and DatagramSocket.receive). Have you thought about using DatagramPacket.setSoTimeout to set a timeout on the socket's receive block, and then catching the SocketTimeoutException when it's thrown by the call to receive() that times out? You should be able to implement this to achieve what you want.

UPDATE: looking further still, it appears that the DatagramSocket.receive method is synchronized. So the way to explain the behavior you're seeing is that you're starting two threads that are attempting to use the same DatagramSocket instance -- if two threads are attempting to execute receive() on the same DatagramSocket instance, one will block the instance until it's done, and the other will be blocked. (There's a post on the Sun forums that describes this, as well.) Might this be what's happening -- you're reusing the same DatagramSocket for both threads?

女皇必胜 2024-08-18 18:26:54

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

It can be because the Java threads are user level threads (opposed to kernel level threads).
One kernel level thread can contain multiple user level threads. However if one user level thread waits for io, the kernel has no way to put only that user level thread on a wait queue, it can only put the whole kernel thread on the wait queue (user level threads are scheduled at the user level, not at the kernel level). As a result, a single user level thread waiting for io can/will block all the other user level threads (from that kernel thread).

叶落知秋 2024-08-18 18:26:54

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

There's really no explanation for the behaviour you're describing, that a read on an InputStream from a Socket should cause "all other threads" to pause. Are you by any chance starting several threads, which all are reading from the same socket and what you actually mean is that all these threads are hanging? In that case, I would expect that the data read from the socket is divided arbitrarily among the threads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文