Search code examples
javamultithreadingjava.util.concurrent

How can I divide into threads using ExecuterService?


I have an array which has ~ 5 000 objects. For each object I'm planning to execute some logic. The logic is the same for each object. I want to do it as fast as i can, so i came to ExecutorService, which is in java.util.cuncurrent. I have decided to work with 100 objects in a thread, so i have divided my total number (~5k) into intervals

private List<Integer> divideIntoIntervals(Integer total)
{
    List<Integer> intervals = new ArrayList<Integer>();
    intervals.add(0);
    int n = total / PART_SIZE;

    int leftover = total % PART_SIZE;
    if(n!=0)
    {
        intervals.add(PART_SIZE);
        for (int i=2; i<=n; i++)
        {
            intervals.add(PART_SIZE*i);
        }
        intervals.add(PART_SIZE*n+leftover);
    }

    return intervals;
}

so, the array would be like: 0, 100, 200, 300, ... , 5000, 5041. What cuncurrent list would you suggest? I'm planning to create logic, which seeks my cuncurrent array for another interval to work with.


Solution

  • You probably don't need a concurrent list. As long as you don't modify the list while your threads do their work, you can just create a separate Runnable that works on its own range and submit those runnables to a ThreadPoolExecutorService with the appropriate number of threads (~50 in your case). The tasks will get distributed evenly between threads automatically:

    ExecutorService executor = Executors.newFixedThreadPool(list.size() / 100 + 1);
    // (+1 in case there are less than 100 items)
    for (int i = 0; i < list.size(); i += 100) {
        final int start = i;
        executor.execute(() -> {
            int end = start + 100;
            if (end > list.size()) {
                end = list.size();
            }
            for (int j = start; j < end; ++j) {
                list.get(j).doYourLogicHere();
            }
        });
    }
    

    If you aren't absolutely sure that you won't modify the list outside of these tasks, then the code should be changed according to however you want to deal with those modifications. For example, if new items can be appended to the list while the processing takes place and you don't care whether those new items are processed or not at this stage, then you may wish to use a CopyOnWriteArrayList and change the inner loop above to use iterators instead of int-based indexing. This will cause the code to use a snapshot of the list taken when the iterator is created (and if there are no modifications while you iterate, there won't be any actual copying). Depending on when the new items are appended, this snapshot may or may not include them, but at least it will be consistent and nothing breaks.