user596186
user596186

Reputation: 589

Dynamically spawn threads Java for a case like this

Suppose I have a List of integers. Each int I have must be multiplied by 100. To do this with a for loop I'd construct something like the following:

for(Integer i : numbers){
  i = i*100;
}

But suppose for performance reasons I wanted to simultaneously spawn a thread for each number in numbers and perform a single multiplication on each thread returning the result to the same List. What would be the best way of doing such a thing?

My actual problem isn't as trivial as multiplication of ints but rather a task that each iteration of the loop takes a substantial amount of time, and so I'd like to do them all at the same time in order to decrease execution time.

Upvotes: 1

Views: 729

Answers (7)

Matt Stephenson
Matt Stephenson

Reputation: 8620

The quick and dirty way to get started is to use a thread pool, such as one returned by Executors.newCachedThreadPool(). Then create tasks that implement Runnable and submit() them to your thread pool. Also read up on the classes and interfaces linked by those Javadocs, lots of cool stuff you can try.

See the concurrency chapter in Effective Java, 2nd ed for a great introduction to multithreaded Java.

Upvotes: 1

stacker
stacker

Reputation: 68972

If it is the only application on a node you should determine which number of threads will finish the job most quickly (max_throughput). This depends on the processor you use how much JIT can optimize your code, so there is no general advise but measure.

After that you could distribute the jobs to a pool of worker threads by numbers modulo max_throughput

Upvotes: 0

Victor Sorokin
Victor Sorokin

Reputation: 12006

If your tasks are independent of each other, you can use Executors framework. Note that you would gain more speed if you create no more threads than you have CPU cores at your disposal.

Sample:

class WorkInstance {
    final int argument;
    final int result;

    WorkInstance(int argument, int result) {
        this.argument = argument;
        this.result = result;
    }

    public String toString() {
        return "WorkInstance{" +
                "argument=" + argument +
                ", result=" + result +
                '}';
    }
}

public class Main {

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        int numOfCores = 4;
        final ExecutorService executor = Executors.newFixedThreadPool(numOfCores);
        List<Integer> toMultiplyBy100 = Arrays.asList(1, 3, 19);
        List<Future<WorkInstance>> tasks = new ArrayList<Future<WorkInstance>>(toMultiplyBy100.size());
        for (final Integer workInstance : toMultiplyBy100)
            tasks.add(executor.submit(new Callable<WorkInstance>() {
                public WorkInstance call() throws Exception {
                    return new WorkInstance(workInstance, workInstance * 100);
                }
            }));

        for (Future<WorkInstance> result : tasks)
            System.out.println("Result: " + result.get());

        executor.shutdown();
    }
}

Upvotes: 2

Savino Sguera
Savino Sguera

Reputation: 3572

I assume you are on a commodity PC. You will at most have N threads executing at the same time on your machine, where N is the # of cores of your CPUs, so most likely in the [1, 4] range. Plus the contention on the shared list.

But even more importantly, the cost of spawning a new thread is much greater than the cost of doing a multiplication. One could have a thread pool... but in this specific case, it's not even worth talking about it. Really.

Upvotes: 0

Thomas
Thomas

Reputation: 88727

Take a look at ThreadPoolExecutor and create a task for each iteration. A prerequisite is that those tasks are independent though.

The use of a thread pool allows you to create a task per iteration but only run as many concurrently as there a threads, since you'd want to reduce the number of thread, for example to the number of cores or hardware threads available. Creating a whole lot of threads would be counter productive since they'd require a lot of context switching which hurts performance.

Upvotes: 0

Reverend Gonzo
Reverend Gonzo

Reputation: 40851

If you can use Java 7, the Fork/Join framework is created for precisely this problem. If not, there is a JSR166 (the fork/join proposal) source code at this link.

Essentially, you would create a task for each step (in your case, for each index in the array) and submit it to a service that can pool threads (the fork part). Then you wait for everything to complete and merge the results (the join part).

The reason to use a service as opposed to launching your own threads, is there can be an overhead in creating threads, and in some cases, you may want to limit the number of threads. For example, if you're on a four CPU machine, it wouldn't make much sense to have more than four threads running concurrently.

Upvotes: 4

Wojciech Owczarczyk
Wojciech Owczarczyk

Reputation: 5735

Spawning a new thread for

each number in numbers

is not a good idea. However, using a fixed thread pool of size matching the number of cores/CPUs might increase your performace slightly.

Upvotes: 1

Related Questions