19

我想知道,在 java 1.6 x64 中有许多线程处于等待状态是多么昂贵。

更具体地说,我正在编写跨多台计算机运行并从一台计算机发送/接收数据的应用程序。我觉得为每台连接的机器和任务设置单独的线程会更舒服,比如 1) 发送数据,2) 接收数据,3) 在连接断开时重新建立连接。因此,假设集群中有 N 个节点,每台机器将为 N-1 个邻居中的每一个拥有 3 个线程。通常会有 12 台机器,相当于 33 个通信线程。

这些线程中的大多数大部分时间都在休眠,因此出于优化目的,我可以减少线程数量并为每个线程分配更多工作。比如,例如。重新建立连接是接收线程的责任。或者发送到所有连接的机器是由单线程完成的。

那么拥有许多睡眠线程是否会对性能产生重大影响?

4

5 回答 5

15

在大多数情况下,休眠线程消耗的资源将是它的堆栈空间。使用 2-threads-per-connection-model(我认为这与您所描述的类似)已知会在连接数量变大时导致很大的可伸缩性问题。

我自己也遇到过这种情况,当连接数超过 500 个连接(大约 1000 个线程)时,您往往会遇到很多出现 OutOfMemoryError 的情况,因为线程堆栈空间使用量超过了最大数量单个进程的内存。至少在我们的案例中,它是在 32 位 Windows 世界上的 Java 中。我猜你可以调整一些东西并走得更远,但最终它只是不是很可扩展,因为你浪费了大量的内存。

如果您需要大量连接,Java NIO(新 IO 或其他)是可行的方法,可以在同一个线程中处理大量连接。

话虽如此,在一个相当现代的服务器上,你不应该遇到少于 100 个线程的问题,即使它可能仍然是资源的浪费。

于 2008-09-19T09:34:09.587 回答
2

在我们切换到 NIO 之前,我们遇到了非常相似的问题,所以我将支持 Liedmans 的建议以使用该框架。你应该可以找到一个教程,但如果你想了解详细信息,我可以推荐Ron Hitchens 的Java NIO

切换到 NIO 增加了我们可以处理的连接数量,这对我们来说非常重要。

于 2008-09-19T10:56:32.990 回答
1

这不会很好地扩展。拥有大量线程意味着 VM 必须花费更多时间进行上下文切换,并且由于每个线程都需要自己的堆栈空间,因此内存使用率会更高。以管道方式处理较少数量的线程会更好,或者将线程池与异步技术一起使用。

于 2008-09-19T09:40:25.937 回答
1

大量线程等同于大量堆栈空间,这会占用您的内存 - 检查您的 -Xss 设置以了解多少,然后进行数学计算。

而且,如果您出于某种原因必须执行 notifyAll() ,那么您当然会唤醒大量额外的线程 - 尽管您可能不需要在建议的架构中这样做。

我不确定您是否可以轻松避免在此模型中每个侦听套接字有一个线程(尽管我对 NIO 知之甚少 - 这甚至可能解决该问题),但请查看java.util.concurrent.Executor接口和它的实现类以一种体面的方式来避免有太多额外的线程挂起。事实上,这ThreadPoolExecutor也可能是管理监听线程的好方法,因此您不会花费太多时间不必要地创建和销毁线程。

于 2008-09-19T10:33:14.107 回答
0

根据我在 C、Lua 和 Python 中所做的测试,您可以使用非常少的代码行来创建自己的睡眠或等待函数,从而创建一个简单的轻量级循环。使用带有您想要到达的未来时间的局部变量,然后在 while 循环中测试当前时间戳。如果您在使用 fps 的范围内,请让等待函数每帧运行一次以节省资源。您需要的精度越高,请考虑使用时钟而不是时间戳,因为时间戳限制为秒。您添加到等待函数中的代码行越多,它变得越不精确并且消耗的资源越多,尽管任何低于 10 行的代码都应该足够快。

于 2016-11-29T09:55:52.817 回答