如何使这段代码更加并发?

时间:2012-08-09 07:21:53

标签: java multithreading concurrency threadpool java.util.concurrent

我有一段类似于以下内容的代码:

final int THREADS = 11;  
BlockingQueue<Future<Long>> futureQueue = new ArrayBlockingQueue<Future<Long>>(THREADS);  
for (int i = 0; i < end; i++, count++) {  
    futureQueue.put(executor.submit(MyRunnable));  
}   
//Use queued results

我如何重构这个以使其更多并发?我在这里监督有什么微妙之处吗?

更新
每个Runnable都应该向服务器发送大量的HTTP请求以进行压力测试。我是否在正确的轨道上?

2 个答案:

答案 0 :(得分:3)

我会用

static final int THREADS = Runnable.getRuntime().availableProcesses();  

ExecutorService service = Executors.newFixedThreadPool(THREADS);

List<Future<Long>> futureQueue = new ArrayList<Future<Long>>(end);  
for (int i = 0; i < end; i++)
    futureQueue.add(executor.submit(new MyRunnable()));  

您正在使用有界队列,如果end > THREADS它将停止。

  

每个Runnable都应该向服务器发送大量的HTTP请求以进行压力测试。我是否在正确的轨道上?

在这种情况下,我将使用以下代码,因为您的代码是IO而不是CPU绑定。

ExecutorService service = Executors.newCachedThreadPool();

如果您拥有超过1000个线程,您可能会从使用NIO中受益,但这只会使您的负载测试器更高效,但这会使代码更加复杂。 (如果您认为这很难,那么编写高效且正确的选择器代码很多更难)

在多台机器上运行测试仪会产生更大的不同。

答案 1 :(得分:3)

使用线程在您的情况下效果不佳。当您拥有CPU密集型作业时,线程池可以很好地工作。在您的情况下,您有一个IO密集型作业 - 它不受您拥有的CPU数量的限制,而是受您可以发送的网络数据包数量的限制。

在这种情况下,NIO中的课程是你的朋友。创建数百个连接并使用NIO selectors查看哪个连接已准备好接收更多数据。

使用这种方法,根本不需要线程;一个CPU核心足以填满GBit以太网连接(~100MB / s)。

[编辑] 当然,您可以创建数百个线程来尝试填充IO通道。但这有一些缺点:

  1. 线程由OS(或小助手库)管理。它们需要内存,每次切换线程时,CPU都必须保存其状态并刷新其缓存。
  2. 如果一个线程只做了少量的工作,那么线程切换可能比做这项工作更昂贵。
  3. 当您使用线程时,您将获得所有常见的线程同步问题。
  4. 没有简单的方法可以确保您拥有适量的线程。如果线程太少,则不会以最佳方式使用IO通道。如果线程太多,则不会以最佳方式使用该通道,因为线程将争取访问它。在这两种情况下,您都无法在开始测试后更改此设置。该系统无法满足需求。
  5. 对于像这样的任务,像Akka这样的框架更适合,因为它避免了所有这些问题,并且使用起来比线程更简单。