我对Java多线程感到困惑

时间:2012-07-23 09:01:27

标签: java multithreading

我正在开发一个程序,可以发送http请求来获取文档。 我已经填写了包含所有请求项的队列:

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循环中,任务是否同时运行?或者任务一个接一个地运行?

谢谢!

6 个答案:

答案 0 :(得分:4)

  

我很困惑,在for循环中,任务是否同时运行?或者任务一个接一个地运行?

使用您发布的代码,它们将逐个运行,因为(假设RequestTaskThread的子类)您已调用run您应该致电start现在您说RequestTask实施Runnable,正确的代码不会调用start(它没有'有一个!)而是new Thread(task);(但看起来你现在收到了关于ExecutorService的好答案,这是另一种方法。)

假设你调用start 而不是在不同的线程上启动它们,那么是的,它们都将并行运行(尽可能多地在硬件上运行)。 / p>

答案 1 :(得分: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();

答案 2 :(得分:2)

目前你正在顺序运行你的线程,你有两种方法来运行线程。(假设RequestTask扩展了Thread)

I.创建线程对象并调用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);
}

答案 3 :(得分:1)

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

答案 4 :(得分: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,它们就会在不同的线程中异步执行。

答案 5 :(得分:0)

我通常倾向于创建我的Threads(或实现Interface的类),然后使用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();
}