2012-07-23 128 views
1

我正在开发一个程序,可以发送http请求来获取文件。 我有填充队列所有请求事项:我很困惑Java多线程

Queue<RequestItem> requestItems = buildRequest4Docs(); 

然后,

int threadNum = requestItems.size(); 
     //ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

     for (int i = 0; i < threadNum; i++) { 
      ResponseInterface response = new CMSGOResponse(); 
      RequestTask task = new RequestTask(requestItems.poll(), this, response); 
      task.run(); 
      //exs.execute(new RequestTask(requestItems.poll(), this, response)); 
     } 
     //exs.shutdown(); 

我很困惑在这里,在for循环,确实任务同时运行或任务的运行呢?一?

谢谢!

+0

类 “RequestTask” 实现 “可运行” – zxi 2012-07-23 09:18:13

回答

4

在你得到它现在的任务也将被逐一执行的方式。如果您取消注释了您现在获得的代码作为注释并对行RequestTask task = new RequestTask(requestItems.poll(), this, response);task.run();进行注释,您将获得并发执行。

所以对于并发执行它看起来像这样:

int threadNum = requestItems.size(); 
ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

for (int i = 0; i < threadNum; i++) { 
    ResponseInterface response = new CMSGOResponse(); 
    exs.execute(new RequestTask(requestItems.poll(), this, response)); 
} 
exs.shutdown(); 
while (! exs.isTerminated()) { 
    try { 
     exs.awaitTermination(1L, TimeUnit.DAYS); 
    } 
    catch (InterruptedException e) { 
     // you may or may not care here, but if you truly want to 
     // wait for the pool to shutdown, just ignore the exception 
     // otherwise you'll have to deal with the exception and 
     // make a decision to drop out of the loop or something else. 
    } 
} 

除此之外,我建议,你不绑定与ExecutorService创建任务的你有量线程数量上班。将它连接到主机系统的处理器数量通常是更好的方法。要获得处理器的使用量:Runtime.getRuntime().availableProcessors()

而在执行器服务中,像这样初始化您放置队列中的项目。但是,很好地工作,而不会提取总大小,而是轮询Queue,直到它不返回其他数据。

我的建议最后的结果看起来是这样的:

final int threadNum = Runtime.getRuntime().availableProcessors(); 
final ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

while (true) { 
    final RequestItem requestItem = requestItems.poll(); 
    if (requestItem == null) { 
     break; 
    } 
    final ResponseInterface response = new CMSGOResponse(); 
    exs.execute(new RequestTask(requestItem , this, response)); 
} 
exs.shutdown(); 
+0

我建议ExecutorService池大小配置比上面更复杂。我会根据他们正在做的事情以及他们的资源约束来配置线程的数量,而不仅仅是CPU的数量(例如,如果RequestTask正在查询远程服务会发生什么) – 2012-07-23 09:21:06

+0

这取决于预期的任务数量。但是,将线程数量设置为任务数量是一个糟糕的主意。如果现在有1000个任务在等待,会发生什么?在这种情况下可能会发生问题。上面的方法是可行的,它不会是最有效的方法,因为线程的构建通常非常昂贵。如果你想要一个非常有效的解决方案,你必须将线程数量扩展到任务数量和处理器数量。如果只有几项任务,你也必须考虑不使用线程。 – Nitram 2012-07-23 09:25:26

+0

如果有10个任务和2个CPU,在上面的代码中,10个任务如何分配给2个线程?在每个线程中,任务是否按顺序运行?我的意思是,如果java能够自动地将任务安排到空闲线程?@Nitram – zxi 2012-07-23 10:00:55

1

您正在当前线程中逐一运行它们。您需要使用ExecutorService来同时运行它们。

4

我很困惑,在for循环中,任务是同时运行还是一个一个的运行?

随着你发布的代码,他们会运行一个接一个,因为(假设RequestTaskThread一个子类)你叫run您应该致电start现在你已经说过RequestTask implements Runnable,正确的代码不会调用start(它没有!),而是new Thread(task);(但它看起来像你现在已经收到关于ExecutorService,这是另一种方式来做到这一个很好的答案。)

假设你电话start启动它们在不同的线程,而不是,那么是的,他们”都会并行运行(尽可能在硬件上运行等)。

2

目前正在运行的线程的顺序,那么你有两种方式来运行的线程(假设RequestTask继承Thread)

I.Either创建线程对象,并调用start()方法。

RequestTask task = new RequestTask(requestItems.poll(), this, response); 
task.start(); // run() method will be called, you don't need to call it 

II.Or创建的ExecutorService

ExecutorService pool = Executors.newFixedThreadPool(poolSize); 
//.... 
for (int i = 0; i < threadNum; i++) { 
    ResponseInterface response = new CMSGOResponse(); 
    RequestTask task = new RequestTask(requestItems.poll(), this, response); 
    pool.execute(task); 
} 
1
I am confused here, in the for loop,does the tasks run simultaneously? Or the tasks run one by one? 

任务将在同一个线程即one by one因为你调用run()宁可start执行,也不会运行任务在新线程中。

 int threadNum = requestItems.size(); 
     ExecutorService exs = Executors.newFixedThreadPool(threadNum); 


     ResponseInterface response = new CMSGOResponse(); 
     RequestTask task = new RequestTask(requestItems.poll(), this, response); 

     exs.execute(task);   
     exs.shutdown(); 

在上述情况下,任务将在新的线程中执行,并尽快分配10个不同的任务ExecutorService他们将在不同的线程异步执行。

0

我通常倾向于创建我的线程(或实现接口的类),然后使用start()方法启动它们。

在你的情况下,由于RequestTask实现Runnable,您可以添加这样的start()方法:

public class RequestTask implements Runnable { 
    Thread t; 
    boolean running; 

    public RequestTask() { 
     t = new Thread(this); 
    } 

    public void start() { 
     running = true; // you could use a setter 
     t.start(); 
    } 

    public void run() { 
     while (running) { 
      // your code goes here 
     } 
    } 
} 

,则:

int threadNum = requestItems.size(); 
RequestTask[] rta = new RequestTask[threadNum]; 

// Create the so-called Threads ... 
for (int i=0;i<threadNum;i++) { 
    rta[i] = new RequestTask(requestItems.poll(), this, new CMSGOResponse()); 
} 

// ... THEN launch them 
for (int i=0;i<threadNum;i++) { 
    rta[i].start(); 
}