使用CompletionService处理大量任务

时间:2014-05-29 03:51:22

标签: java multithreading executorservice hazelcast completion-service

我需要在多核机器上处理大量(> 1亿)请求(每个请求都是处理数据文件中的一行,并涉及远程系统的一些I / O.虽然详情没关系,具体任务是从一些数据文件加载分布式Hazelcast映射)。执行将通过ThreadPoolExecutor处理。一个线程将读取该文件,然后将数据提交给多个独立的线程以将其放入映射中。该机器有32个核心,因此有足够的可用于并行加载地图。

由于请求数量很多,创建任务并将它们排队到执行程序服务的常用方法是不可行的,因为排队的任务会占用太多内存。

带来了ExecutorCompletionService。有了它,一个任务将在前一个操作完成时提交,通过调用take()(或poll(),如果适用)可以知道。当使用执行程序服务的所有线程时,这将正常工作。但是,“加载所有线程”尚未完成。有两个阶段:

  • 填满队列:虽然池中仍有未使用的线程,但是将任务提交给ExecutorCompletionService并且不要等到提交更多

  • 提供队列:一旦线程全部被使用,只需在上一个任务完成后提交任务。因此,行将尽快送达,但不会更快,也不会排队。

以上可以编码,但我想知道上面的逻辑是否已经实现,我不知何故错过了它。我问,因为它看起来是一种常见的情况。

2 个答案:

答案 0 :(得分:4)

您可以在创建BlockingQueue时指定ThreadPoolExecutor实施。如果您要避免的是创建多余的Runnable个对象,那么您可以使用有界BlockingQueue,例如ArrayBlockingQueue有一个线程将项目推送到队列,当队列达到容量时,该队列将被阻止。

答案 1 :(得分:-1)

如果我理解你的要求,(如果我错了就纠正我)那么你需要一个机制,其中有几个任务,你需要最多n个任务并行执行,其他任务应该在队列中等待,但是一旦你提交了一个任务,那么你就不想闲逛或让线程提交任务忙碌,它可以继续它的工作

对于相同的情况,我们使用LinkedBlockingQueueThread的混合,我相信一个简单的函数可以帮助您理解,

private final LinkedBlockingQueue<YourTaskObjType> EnqueuedTasks;

private void initTasksProcessingThreads(int numberOfThreads) 
{
    EnqueuedTasks= new LinkedBlockingQueue<YourTaskObjType>();
    for (int i = 0; i < numberOfThreads; i++) 
    {
        // each thread will run forever and process incoming
        //Change requests
        Thread worker = new Thread(new Runnable() 
        {               
            public void run() 
            {
                while (true) 
                {
                    try 
                    {   
                        YourTaskObjType task = EnqueuedTasks.take(); //This will wait infinitely until tasks are available
                        PerformTask(task); //Your function which will perform the task operation
                    } 
                    catch (InterruptedException e) 
                    {                                                                
                        Thread.currentThread().interrupt();
                        return;
                    } 
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        });         
        worker.start();
    }
}

然后,您可以使用一个简单的函数将任务添加到LinkedBlockingQueue

public void AddTask(YourTaskObjType TaskObj)
{
    EnqueuedTasks.put(TaskObj);                         
}