代码之家  ›  专栏  ›  技术社区  ›  Robin

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

  •  0
  • Robin  · 技术社区  · 15 年前

    我有一个Java客户端,它通过HTTP访问服务器端,生成几个小的请求来加载每个新的数据页。我们维护一个线程池来处理所有非UI处理,所以任何后台客户端任务以及任何想要连接到服务器的任务。我一直在研究一些性能问题,我不确定我们是否已经尽可能地设置了线程池。目前,我们使用核心池大小为8的线程池执行器,工作队列使用LinkedBlockingQueue,因此最大池大小被忽略。毫无疑问,在所有情况下都要做这件事是不简单的,但是否有任何最佳实践。我现在的想法是

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

    基本上,我现在担心的是服务器端偶尔出现的性能问题会导致不相关的客户端处理由于线程池大小的上限而停止。我担心无法绑定,这是对客户机上的线程管理的额外冲击,可能只是两种邪恶中的一种。

    有什么建议、最佳实践或有用的参考资料吗? 干杯, 罗宾

    4 回复  |  直到 15 年前
        1
  •  1
  •   Fried Hoeben    15 年前

    听起来您可能更好地限制队列大小:当有许多请求排队时,您的应用程序的行为是否仍然正常(所有任务都可以长时间排队,对其他任务来说是否更重要)?如果仍有排队的任务剩余,并且用户退出应用程序,会发生什么情况?如果队列越来越大,那么服务器是否有可能(很快)赶上,完全向用户隐藏问题?

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

    对于真正的后台任务,保持一个单独的池,队列较长,但不能无限长。定义此池在增长或用户希望退出但仍有任务时的优雅行为,应该发生什么?

        2
  •  1
  •   alphazero    15 年前

    一般来说,网络延迟很容易比在客户机端内存分配或线程管理方面可能发生的任何事情高出几个数量级。因此,作为一般规则,如果你遇到了性能瓶颈,首先看一下网络链接。

    如果问题是您的服务器根本无法跟上来自客户机的请求,那么在客户机端增加线程并不能帮助解决问题:您只需要让8个线程等待对更多线程的响应就可以了(而且您甚至可以通过增加服务器端的负载来加重服务器端的问题,因为较高的nu它正在管理的连接数)。

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

        3
  •  1
  •   kdgregory    15 年前

    AS 阿尔法诺 说,如果你遇到了瓶颈,不管你使用什么方法,你的客户端等待工作的数量都会继续增长。

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

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

    如果你使用 LinkedBlockingQueue.offer() 在一个有边界的队列上,您将立即得到一个表示队列已满的响应,并可以采取诸如禁用某些应用程序功能、弹出对话框之类的操作。然而,这将需要您做更多的工作,特别是如果可以从多个地方提交请求。我建议,如果您还没有,可以在服务器队列上创建一个支持GUI的层,以提供常见的行为。

    当然,从来没有打过电话 LinkedBlockingQueue.put() 从事件线程(除非您不介意挂起的客户机,即)。

        4
  •  0
  •   Joel    15 年前

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

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