睡眠线程和等待线程消耗多少资源
我想知道,在Java 1.6 x64中,有许多线程处于等待状态是多么昂贵。
更具体地说,我正在编写可在多台计算机上运行的应用程序,该应用程序可将数据从一台计算机发送到另一台计算机。我为每个连接的机器和任务都拥有单独的线程感到更自在,例如1)发送数据,2)接收数据,3)断开连接时重新建立连接。因此,假设群集中有N个节点,则每台计算机将为N-1个邻居中的每个邻居拥有3个线程。通常,将有12台计算机,涉及33个通信线程。
这些线程中的大多数都会在大多数时间处于休眠状态,因此出于优化目的,我可以减少线程数量并为每个线程分配更多的工作。举例来说。重新建立连接是接收线程的责任。或者发送到所有连接的计算机是通过单线程完成的。
那么,对具有多个睡眠线程的性能有何重大影响?
解决方案
在大多数情况下,睡眠线程消耗的资源将是其堆栈空间。我认为使用2-threads-per-connection-model(每个连接2线程模型)与我们所描述的模型类似,因此,当连接数量增加时,这会导致严重的可伸缩性问题。
我本人就一直处于这种情况,并且当连接数超过500个连接(大约一千个线程)时,由于线程堆栈空间使用量超过了最大数量,我们倾向于陷入OutOfMemoryError的情况单个进程的内存。至少在我们的例子中,这是在32位Windows环境中的Java中。我猜,我们可以调整内容并进一步扩展,但是最终它扩展性不是很好,因为我们浪费了大量内存。
如果需要大量的连接,则可以使用Java NIO(新IO或者其他),从而可以在同一线程中处理许多连接。
话虽如此,在相当现代的服务器上使用少于100个线程就不会遇到太多问题,即使它仍然可能浪费资源。
这不会很好地扩展。拥有大量线程意味着VM必须花费更多时间进行上下文切换,并且由于每个线程都需要自己的堆栈空间,因此内存使用率将更高。我们最好以流水线方式处理较少数量的线程,或者将线程池与异步技术一起使用。
许多线程等于大量堆栈空间,这会占用内存,请检查-Xss设置的大小,然后进行数学计算。
而且,如果由于某种原因不得不执行notifyAll(),那么尽管我们可能不需要在提议的体系结构中执行此操作,但是我们当然会唤醒大量额外的线程。
我不确定我们是否可以轻松避免在此模型中每个侦听套接字使用一个线程(尽管我对NIO知之甚少,即使解决了该问题,也可以解决),但请看一下java.util.concurrent.Executor接口及其以一种体面的方式实现类,以避免产生过多的添加线程。确实,ThreadPoolExecutor
可能也是管理监听线程的好方法,因此我们不必花费太多时间不必要地创建和销毁线程。
在切换到NIO之前,我们遇到了几乎相同的问题,因此,我将第二次推荐Liedmans建议使用该框架。我们应该可以找到一个教程,但是如果我们想了解详细信息,我可以推荐Ron Hitchens的Java NIO。
切换到NIO可以增加很多我们可以处理的连接数量,这对于我们来说确实至关重要。