最小化Java线程上下文切换开销

Bin*_*mas 11 java performance multithreading solaris threadpool

我有一个在Sun 1.6 32位VM/Solaris 10(x86)/ Nahelem 8核(每个核心2个线程)上运行的Java应用程序.

应用程序中的特定用例是响应某些外部消息.在我的性能测试环境中,当我准备并在接收外部输入的同一线程中发送响应时,我获得大约50美元的优势,而不是当我将消息传递给单独的线程来发送响应时.我使用的是ThreadPoolExecutorSynchronousQueue做切换.

在你的经历中是什么 接受将任务调度到线程池并将其拾取执行之间的预期延迟?过去有什么想法可以改善这一点?

Jon*_*eet 12

"可接受的延迟"完全取决于您的申请.如果您有非常严格的延迟要求,那么处理同一线程上的所有内容确实会有所帮助.幸运的是,大多数应用程序没有那么严格的要求.

当然,如果只有一个线程能够接收请求,那么占用该线程以计算响应将意味着您不能接受任何其他请求.根据您正在做的事情,您可以使用异步IO(等)来避免"每个请求的线程"模型,但它的IMO要困难得多,并且最终仍然会进行线程上下文切换.

有时候排队请求是合适的,以避免过多的线程处理它们:如果你的处理是CPU限制的,那么拥有数百个线程没有多大意义 - 最好有一个生产者/消费者的任务队列并在每个核心大约一个线程.ThreadPoolExecutor如果你正确地设置它,基本上会做什么.如果您的请求花费大量时间等待外部服务(包括磁盘,但主要是其他网络服务),那么这也不会有效......此时您需要使用异步执行模型,无论何时您可能会创建一个使用阻塞调用进行核心空闲,或者你采用线程上下文切换命中并拥有大量线程,依靠线程调度程序使其运行良好.

底线是延迟要求可能很难 - 根据我的经验,它们比吞吐量要求更加困难,因为它们更难以扩展.它确实取决于上下文.


Dew*_*wfy 0

不是相同的任务,但是“是” - 队列通常用于时间关键的任务。我们集中精力避免同步处理事件。查看以下提示

  • 不要使用同步容器(数组、列表、映射...)。考虑每个线程容器。
  • 我们使用了循环线程池。该池由预先分配的线程组成,并且(!)恰好有一个事件监听出现,没有任何队列。当事件引发时,线程将从循环中删除,另一个线程成为侦听器。处理完成后,线程返回到池中。