为Java RIA客户端应用程序配置Threadpool的最佳方法

时间:2009-12-16 11:58:01

标签: java concurrency multithreading client-server rich-internet-application

我有一个Java客户端,通过HTTP访问我们的服务器端,发出几个小的请求来加载每个新的数据页面。我们维护一个线程池来处理所有非UI处理,因此任何后台客户端任务和任何想要与服务器建立连接的任务。我一直在研究一些性能问题,我不确定我们是否已经尽可能地设置了线程池。目前我们使用CorePoolExecutor,核心池大小为8,我们使用LinkedBlockingQueue作为工作队列,因此忽略最大池大小。毫无疑问,在所有情况下都没有这么简单的回答,但是有没有最好的做法。我此刻的想法是

1)我将切换到使用SynchronousQueue而不是LinkedBlockingQueue,以便池可以增长到最大池大小数字。 2)我将最大池大小设置为无限制。

基本上我目前担心的是服务器端的偶然性能问题会导致无关的客户端处理由于线程池大小的上限而停止。我对无限制的恐惧是在客户端管理这些线程的额外打击,可能只是2个恶魔中的更好。

有任何建议,最佳做法或有用的参考资料吗? 干杯, 罗宾

4 个答案:

答案 0 :(得分:1)

通常,网络延迟比在客户端的内存分配或线程管理方面可能发生的任何事情都要高出几个数量级。因此,作为一般规则,如果您遇到性能瓶颈,请首先查看网络链接。

如果问题是你的服务器根本无法跟上来自客户端的请求,那么在客户端增加线程并不会有任何问题:你只需要等待8个线程等待获得响应更多线程等待(并且由于管理的连接数量增加,您甚至可能通过增加其负载来加剧服务器端问题。)

JDK中的两个并发队列都是高性能的;选择真的归结为使用语义。如果您有非阻塞管道,那么使用非阻塞队列更自然。如果你不这样做,那么使用阻塞队列会更有意义。 (您始终可以指定Integer.MAX_VALUE作为限制)。如果不需要FIFO处理,请确保不指定公平排序,因为这会导致性能大幅下降。

答案 1 :(得分:1)

听起来你可能更好地限制队列大小:当有许多请求排队时你的应用程序是否仍能正常运行(所有任务排队很长时间都可以接受,对于一些更重要的是其他)?如果仍有排队的任务并且用户退出应用程序会发生什么?如果队列变得非常大,那么服务器是否有可能赶上(很快就会)完全隐藏用户的问题?

我想为需要响应的请求创建一个队列来更新用户界面,并保持其队列非常小。如果此队列太大,请通知用户。

对于真实的后台任务,保留一个单独的池,具有更长的队列,但不是无限的。为此池定义优雅行为,或者当用户想要退出但是还有剩下的任务时,会发生什么?

答案 2 :(得分:1)

正如 alphazero 所说,如果你遇到了瓶颈,无论你使用什么方法,你的客户端等待工作的数量都会继续增长。

真正的问题是你想如何处理瓶颈问题。或者更准确地说,您希望用户如何处理瓶颈。

如果您使用无界限队列,则无法获得瓶颈已发生的反馈。在某些应用程序中,这很好:如果用户正在启动异步任务,那么就不需要报告积压(假设它最终会清除)。但是,如果用户在执行下一个客户端任务之前需要等待响应,则这非常糟糕。

如果在有界队列上使用LinkedBlockingQueue.offer(),那么您将立即得到一个响应,表明队列已满,并且可以执行操作,例如禁用某些应用程序功能,弹出对话框等等。但是,这将需要您做更多的工作,特别是如果可以从多个地方提交请求。我建议,如果你还没有,你可以在服务器队列上创建一个GUI感知层来提供常见的行为。

当然,永远不要从事件线程中调用LinkedBlockingQueue.put()(除非你不介意挂起的客户端)。

答案 3 :(得分:0)

为什么不创建一个无界的队列,但是当队列达到一定的大小时,拒绝任务(甚至可能通知用户服务器正忙(取决于应用程序!))?然后,您可以记录此事件并找出服务器端发生的备份以进行备份。此外,除非您连接到多个远程服务器,否则池中可能没有多少线程可用,尽管这取决于您的应用程序及其作用以及与之对话的人员。

拥有无限制的游泳池通常很危险,因为它通常不会优雅地降级。最好记录问题,发出警报,防止进一步的操作排队,并找出如何解决服务器端问题(如果存在问题),以防止再次发生这种情况。