rid
rid

Reputation: 63442

Is fork / join multithreaded?

If I have 2 CPUs and schedule 1000 tasks for the fork / join framework to work on, will the tasks be executed in a maximum of 2 at a time, or will more tasks be executed in parallel on the same CPU? (say, maybe one task is waiting for I/O, in which case the CPU would become idle and another thread could run)

Upvotes: 2

Views: 3088

Answers (5)

radiantRazor
radiantRazor

Reputation: 489

By default, the Fork/Join Framework tries to maintain the number of threads equal to one less than the number of cores (if a single core machine, then one thread is created). You can see this code in makeCommonPool method in ForkJoinPool class.

If you think that this under-utilises your CPU, you can provide a custom value for parallelism.

But most interestingly, there is a way to make ForkJoinPool create more threads when the current thread occupying the CPU blocks on IO. All you have to is to implement the code block which actually blocks on the IO inside an implementation of the block method of the ForkJoinPool.ManagedBlocker object, and pass that ManagedBlocker object to the managedBlock method of the ForkJoinPool class. When this is done, the ForkJoinPool checks if the current thread calling this method is an instance of a ForkJoinPoolWorkerThread. If it is, the ForkjoinPool compensates by creating new threads which can take over the CPU.

ForkJoinPool fjp = ForkJoinPool.common();
Runnable task = new Runnable(){
  public void run(){
    //Some cpu-intensive code
    ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker(){
      public boolean isReleasable(){
        //return true if an IO/blocking operation is to be done.
      }

      public boolean block(){
       //Do an IO Operation here
       //return true if all blocking code has finished execution.
       //return false if more blocking code is yet to execute.
      }

    });
    //Some more CPU intensive code here
  }
};
fjp.submit(task);

Upvotes: 0

rid
rid

Reputation: 63442

I made a test to verify this:

import java.util.concurrent.*;

public class Test {
    private static class TestAction extends RecursiveAction {
        private int i;

        public TestAction(int i) {
            this.i = i;
        }

        protected void compute() {
            if (i == 0) {
                invokeAll(new TestAction(1), new TestAction(2), new TestAction(3),
                          new TestAction(4), new TestAction(5), new TestAction(6));
                return;   
            }             
            System.out.println(i + " start");
            try { Thread.sleep(2000); } catch (Exception e) { }
            System.out.println(i + " end"); 
        }   
    }       

    public static void main(String[] args) {
        new ForkJoinPool().invoke(new TestAction(0));
    }   
}       

The results of that running with the reference Oracle implementation is:

1 start
6 start <- wait 2 seconds
1 end
2 start
6 end
5 start <- wait 2 seconds
2 end
3 start
5 end
4 start <- wait 2 seconds
4 end
3 end

The same behavior is consistent on both Linux and Mac OS X.

So the answer to the question is: yes, the tasks will be executed on exactly the number of CPUs specified by the parallelism parameter (or the total available CPUs by default). If CPU time becomes available and the tasks simply block waiting for something, then the framework will do nothing automatically to run other tasks.

Since the documentation I've seen so far is pretty vague about what exactly the framework is supposed to do if the CPU is free, this could be an implementation detail.

Upvotes: 1

Wug
Wug

Reputation: 13196

If you do not include any restriction yourself, none will be applied and Java will fork as many threads as it can (maybe all 1000 depending on system restrictions). This is not ideal. If you're doing a computation which is likely to have some IO time but not be IO bound even at large amounts of concurrent processing, you might be able to justify running one more thread then the available number of CPUs. Running all 1000 at once would not be wise.

If I have 2 CPUs and schedule 1000 tasks for the fork / join framework to work on, will the tasks be executed in a maximum of 2 at a time, or will more tasks be executed in parallel on the same CPU?

If you have a dual core CPU, you can only actually execute 2 threads at once.

Upvotes: 5

David Conrad
David Conrad

Reputation: 16359

According to the ForkJoin documentation:

A ForkJoinPool is constructed with a given target parallelism level; by default, equal to the number of available processors. The pool attempts to maintain enough active (or available) threads by dynamically adding, suspending, or resuming internal worker threads, even if some tasks are stalled waiting to join others. However, no such adjustments are guaranteed in the face of blocked IO or other unmanaged synchronization.

So it will probably run them two at a time on your 2 CPUs, possibly four at a time if the CPUs are hyperthreaded (I'm not certain). If you aren't happy with the default level of parallelism, you can specify a requested level of parallelism by calling the ForkJoinPool constructor that takes the level of parallelism as a parameter.

Upvotes: 3

Avada Kedavra
Avada Kedavra

Reputation: 8691

Is hyperthreading enabled on the cpu? If so you may run 2+ processes at the same time.

Hyper-threading works by duplicating certain sections of the processor—those that store the architectural state—but not duplicating the main execution resources. This allows a hyper-threading processor to appear as two "logical" processors to the host operating system, allowing the operating system to schedule two threads or processes simultaneously.

Upvotes: 1

Related Questions