I just tried to see if breaking down the tasks as much as I can using Fork Join as a fun exercise to get to know the library better (also because I thought dividing the task down into smaller tasks and processing it parallelly would take less time) and contrasted it with a simple for loop.
public class misc {
public void getMissingNumbers(int[] numbers){
for (int i=0; i<numbers.length -1; i++){
int current = numbers[i];
int next = numbers[i+1];
if(current+1 != next){
System.out.println("Problem! - "+current+" "+next);
}
}
}
public static void main(String []args){
int[] range = IntStream.rangeClosed(1, 50_000_000).toArray();
int index = 50000;
range[index] = range[index-1]; //duplicate
index = 390;
range[index] = range[index-1];
index = 500390;
range[index] = range[index-1];
index = 2500390;
range[index] = range[index-1];
ZonedDateTime now = ZonedDateTime.now();
misc m = new misc();
m.getMissingNumbers(range);
System.out.printf("%s exec time: %dms\n",
m.getClass().getSimpleName(),
ChronoUnit.MILLIS.between(now, ZonedDateTime.now()));
now = ZonedDateTime.now();
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
breakDownRecursively bdr = new breakDownRecursively(range);
forkJoinPool.invoke(bdr);
System.out.printf("%s exec time: %dms\n",
bdr.getClass().getSimpleName(),
ChronoUnit.MILLIS.between(now, ZonedDateTime.now()));
}
}
class breakDownRecursively extends RecursiveAction {
private final int[] arr;
private final ArrayList<Integer> arrlst = new ArrayList<>();
public breakDownRecursively(int[] arr) {
this.arr = arr;
}
public void compute() {
int n = arr.length;
if (arr.length < 2) return;
int mid = arr.length / 2;
int[] left = new int[mid];
System.arraycopy(arr, 0, left, 0, mid);
int[] right = new int[arr.length - mid];
System.arraycopy(arr, mid, right, 0, arr.length - mid);
invokeAll(new breakDownRecursively(left), new breakDownRecursively(right));
compare(left, right);
}
private void compare(int[] left, int[] right) {
if (left.length == 1 && right.length == 1) {
if (left[0]+1 != right[0]) {
//System.out.println("Problem! - "+left[0]+" "+right[0]);
}
}
}
}
Output:
Problem! - 390 390
Problem! - 390 392
Problem! - 50000 50000
Problem! - 50000 50002
Problem! - 500390 500390
Problem! - 500390 500392
Problem! - 2500390 2500390
Problem! - 2500390 2500392
misc exec time: 60ms
Problem! - 390 392
Problem! - 500390 500392
Problem! - 2500390 2500392
breakDownRecursively exec time: 2435ms
I suppose I probably made a mistake somewhere during implementation of the fork join, but at the very least you should see that a for loop isn't THAT bad.
and when I used Runnable:
int mid = range.length/2;
int[] half1 = new int[mid+1];
System.arraycopy(range, 0, half1, 0, mid+1);
int[] half2 = new int[mid];
System.arraycopy(range, mid, half2, 0, range.length - mid);
RunnableTask r1 = new RunnableTask(half1);
RunnableTask r2 = new RunnableTask(half2);
now = ZonedDateTime.now();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.printf("%s exec time: %dms\n",
r1.getClass().getSimpleName(),
ChronoUnit.MILLIS.between(now, ZonedDateTime.now()));
class RunnableTask implements Runnable{
private final int[] arr;
public RunnableTask(int[] arr) {
this.arr = arr;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i=0; i<arr.length -1; i++){
int current = arr[i];
int next = arr[i+1];
if(current+1 != next){
System.out.println("Problem! - "+current+" "+next);
}
}
}
}
Output:
Problem! - 390 390
Problem! - 390 392
Problem! - 50000 50000
Problem! - 50000 50002
Problem! - 500390 500390
Problem! - 500390 500392
Problem! - 2500390 2500390
Problem! - 2500390 2500392
RunnableTask exec time: 49ms
Only slightly better than a for loop.