Java 7 brings and/or improves thread management to handle heavy and complex tasks.
You can use threads, ExecutorServices and this: ForkJoinPool.
There is an increasing developers movement to coding in a functional state of mind, using Ruby, Scala, Clojure and other similar programming languages. Java 8 will follow this path too, with lambdas. If you are not using a functional approach in programming, I invite you to do so, its a very different way of thinking where the “divide to conquer” its a must!
In Java 7 you can use this way of thinking to resolve complicated problems, the ones where its necessary to think recursively where you can split a heavy task in simples ones, like when you are sorting a big list using quick sort, transverse a file system including every folder and file, etc. These are problems that seems complicated at first, but thinking recursively it turns out to be very simple tasks.
The main algorithm to implement a recursively task its always something like:
- What is the stop condition? (Here you return a “real” value)
- Call the method recursively calling it itself with some sort of improvement in the parameters, like if you are in a for.. loop.
For instance, long factorial(long n)
- stop condition: if( n <= 1) return 1;
- calling recursively like a loop: return n * factorial(n-1)
Has you know by now, the factorial(n-1) will have to stop in the future, because n-1 its decreasing until it reaches n <= 1, and then n *
In Java 7 you have a Class ForkJoinPool that automatically handle threads to execute the smaller tasks like the above: n and factorial(n-1).
The recursively method will always be the protected Long compute(), which must be an @override because the class will extend: RecursiveTask
In the example below, I have implemented a very simple example to calculate the sum between 2 numbers, using recursive smaller tasks.
I start with some range, if the stop condition (end – start), its below 10, then I return the sum between the start and end, otherwise I split the range in 2 parts, the first one executes concurrently (using fork witch puts the thread in the ForkJoinPool) the second half of (end – start) and the first one computes the sum delegating its execution to the compute method (itself!), or the other half.
Observe the last return: return t2.compute() + t1.join(); where the second thread calls the compute and then waits for the fork previously executed as the first thread!
1 |
<span style="color: #0000ff">import</span> java.util.concurrent.ForkJoinPool; |
1 |
<span style="color: #0000ff">import</span> java.util.concurrent.RecursiveTask; |
1 |
  |
1 |
<span style="color: #008000">/**</span> |
1 |
<span style="color: #008000"> * Calculates a Big Sum recursively using RecursiveTask and ForkJoinPool</span> |
1 |
<span style="color: #008000"> * @author JoseCruz</span> |
1 |
<span style="color: #008000"> *</span> |
1 |
<span style="color: #008000"> */</span> |
1 |
<span style="color: #0000ff">class</span> BigSUM <span style="color: #0000ff">extends</span> RecursiveTask<Long> { |
1 |
<span style="color: #0000ff">private</span> <span style="color: #0000ff">final</span> <span style="color: #0000ff">long</span> start; |
1 |
<span style="color: #0000ff">private</span> <span style="color: #0000ff">final</span> <span style="color: #0000ff">long</span> end; |
1 |
1 |
BigSUM(<span style="color: #0000ff">long</span> s, <span style="color: #0000ff">long</span> e) { |
1 |
<span style="color: #0000ff">super</span>(); |
1 |
<span style="color: #0000ff">this</span>.start = s; |
1 |
<span style="color: #0000ff">this</span>.end = e; |
1 |
} |
1 |
1 |
<span style="color: #008000">// compute sum</span> |
1 |
@Override |
1 |
<span style="color: #0000ff">protected</span> Long compute() { |
1 |
1 |
<span style="color: #008000">// Is it is small enough just for one thread I will handle it!</span> |
1 |
<span style="color: #0000ff">if</span>(end - start < 10) { |
1 |
1 |
<span style="color: #0000ff">long</span> localSoma = 0; |
1 |
<span style="color: #0000ff">for</span>(<span style="color: #0000ff">long</span> s = start; s <= end; s++) { |
1 |
localSoma += s; |
1 |
} |
1 |
1 |
<span style="color: #008000">// The main point of return for the recursive "loop"</span> |
1 |
<span style="color: #0000ff">return</span> localSoma; |
1 |
} |
1 |
1 |
<span style="color: #008000">// Lets split the effort!</span> |
1 |
BigSUM t1 = <span style="color: #0000ff">new</span> BigSUM(start, (end-start)/2+start); |
1 |
BigSUM t2 = <span style="color: #0000ff">new</span> BigSUM((end-start)/2+start+1, end); |
1 |
  |
1 |
<span style="color: #008000">// like cloning..!</span> |
1 |
t1.fork(); |
1 |
1 |
<span style="color: #0000ff">return</span> t2.compute() + t1.join(); |
1 |
} |
1 |
1 |
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> main(String...args) { |
1 |
1 |
<span style="color: #008000">// You can get the available processores and use it to initialize the ForkJoinPool</span> |
1 |
<span style="color: #0000ff">int</span> processors = Runtime.getRuntime().availableProcessors(); |
1 |
ForkJoinPool jfp = <span style="color: #0000ff">new</span> ForkJoinPool(processors); |
1 |
1 |
<span style="color: #008000">// a big number...</span> |
1 |
BigSUM t = <span style="color: #0000ff">new</span> BigSUM(0, 10_000_000L); |
1 |
1 |
<span style="color: #008000">// calculate the sum using lots of threads</span> |
1 |
Long result = jfp.invoke(t); |
1 |
1 |
System.out.println(<span style="color: #006080">"And the sum is "</span> + result); |
1 |
1 |
} |
1 |
} |
I think the code its very clear and simple, if you have questions or comments don’t hesitate to post them!
This Is a very useful tool to resolve complex problems that I really invite you to learn and use it!