I am trying to apply get faster output through threads. Just doing a small POC sort.
Suppose I have a problem statement to find all the the numbers in an array who have odd occurrence.
Following is my attempt for both sequentially and parallel.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class Test1 {
final static Map<Integer, Integer> mymap = new HashMap<>();
static Map<Integer, AtomicInteger> mymap1 = new ConcurrentHashMap<>();
public static void generateData(final int[] arr) {
final Random aRandom = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = aRandom.nextInt(10);
}
}
public static void calculateAllOddOccurrence(final int[] arr) {
for (int i = 0; i < arr.length; i++) {
if (mymap.containsKey(arr[i])) {
mymap.put(arr[i], mymap.get(arr[i]) + 1);
} else {
mymap.put(arr[i], 1);
}
}
for (final Map.Entry<Integer, Integer> entry : mymap.entrySet()) {
if (entry.getValue() % 2 != 0) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
public static void calculateAllOddOccurrenceThread(final int[] arr) {
final ExecutorService executor = Executors.newFixedThreadPool(10);
final List<Future<?>> results = new ArrayList<>();
;
final int range = arr.length / 10;
for (int count = 0; count < 10; ++count) {
final int startAt = count * range;
final int endAt = startAt + range;
executor.submit(() -> {
for (int i = startAt; i < endAt; i++) {
if (mymap1.containsKey(arr[i])) {
final AtomicInteger accumulator = mymap1.get(arr[i]);
accumulator.incrementAndGet();
mymap1.put(arr[i], accumulator);
} else {
mymap1.put(arr[i], new AtomicInteger(1));
}
}
});
}
awaitTerminationAfterShutdown(executor);
for (final Entry<Integer, AtomicInteger> entry : mymap1.entrySet()) {
if (entry.getValue().get() % 2 != 0) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
public static void calculateAllOddOccurrenceStream(final int[] arr) {
final ConcurrentMap<Integer, List<Integer>> map2 = Arrays.stream(arr).parallel().boxed().collect(Collectors.groupingByConcurrent(i -> i));
map2.entrySet().stream().parallel().filter(e -> e.getValue().size() % 2 != 0).forEach(entry -> System.out.println(entry.getKey() + "=" + entry.getValue().size()));
}
public static void awaitTerminationAfterShutdown(final ExecutorService threadPool) {
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
threadPool.shutdownNow();
}
} catch (final InterruptedException ex) {
threadPool.shutdownNow();
Thread.currentThread().interrupt();
}
}
public static void main(final String... doYourBest) {
final int[] arr = new int[200000000];
generateData(arr);
long starttime = System.currentTimeMillis();
calculateAllOddOccurrence(arr);
System.out.println("Total time=" + (System.currentTimeMillis() - starttime));
starttime = System.currentTimeMillis();
calculateAllOddOccurrenceStream(arr);
System.out.println("Total time Thread=" + (System.currentTimeMillis() - starttime));
}
}
Output:
1=20003685
2=20000961
3=19991311
5=20006433
7=19995737
8=19999463
Total time=3418
5=20006433
7=19995737
1=20003685
8=19999463
2=20000961
3=19991311
Total time Thread=19640
Parallel execution (calculateAllOddOccurrenceStream ) is taking more time. What is the best way to process an array in parallel and then merge the result?
My goal is not to find the fastest algorithm, but to use any algorithm and try to run on in different threads such that they are processing different part of array simultaneously.