Please note that multi-threading does not necessarily increase speed. Multi-threading is primarily used in reducing the idle CPU cycles by preventing unnecessary sleeps and so on.
There is not much I can help with what you have provided, however, I think you can start by doing something like this:
- Use thread safe data structures. This is a must. If you miss this
step, your software will break down, eventually. And you will have a
very hard time detecting the cause. (e.g. if you have an ArrayList,
use thread safe one)
- You can start trying out multi-threading by removing the for loop
and using a thread for each execution, instead. If your for loop
size is more than the amount of your threads, you're going to have
to enqueue them.
- You have a final calculation that requires all other threads to
finish. You can use a CountDownLatch, wait()/notifyAll() or
synchronized() depending on your implementation.
- Execute your final calculation.
EDIT
In response to (2):
Your current execution is this:
for (int i = 0; i < mylist.size(); i++) {
some_processes();
}
// then start calculation on all hashmaps
calculate_all();
Now, to remove the "for" loops, your can first start by increasing the "for" loops. e.g:
// Assuming mylist.size() is around 500 and you want, say 5, hardcoded multi-thrads
Thread_1:
for (int i = 0; i < 100; i++) {
some_processes();
}
Thread_2:
for (int i = 100; i < 200; i++) {
some_processes();
}
Thread_3:
for (int i = 200; i < 300; i++) {
some_processes();
}
Thread_4:
for (int i = 300; i < 400; i++) {
some_processes();
}
Thread_5:
for (int i = 400; i < mylist.size(); i++) {
some_processes();
}
// Now you can use these threads as such:
CountDownLatch latch = new CountDownLatch(5);
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new Thread1(latch));
executor.submit(new Thread2(latch));
executor.submit(new Thread3(latch));
executor.submit(new Thread4(latch));
executor.submit(new Thread5(latch));
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
// then start calculation on all hashmaps
calculate_all();
There are a couple of disadvantages of this method as you can see. For example, what if the list size becomes, say 380? Then you have an idle thread. Also, what if you want more than 5 threads?
So at this point, you can further increase the amount of "for" loops by making them loop less and less. At maximum, "for loop count" == "thread count", effectively removes your for loop. So technically, you need "mylist.size()" amount of threads. You can do an implementation of this as such:
// Allow a maximum amount of threads, say mylist.size(). I used LinkedBlockingDeque here because you might choose something lower than mylist.size().
BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>(mylist.size());
CountDownLatch latch = new CountDownLatch(mylist.size());
new Thread(new add_some_processes_w_single_loop_for_loop_to_queue(queue, latch)).start();
new Thread(new take_finished_processes_from_queue(queue)).start();
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
// then start calculation on all hashmaps
calculate_all();
Notice that with this arrangement, we have removed your initial "for" loop and instead created another one that just submits new threads as the queue is emptied. You can check BlockingQueue examples with producer and consumer applications. For example see: BlockingQueue examples
EDIT 2
A simple implementation of Future might be as shown:
ExecutorService executorService = Executors.newCachedThreadPool();
Future future1, future2, future3, future4, future5, future6;
for (int i = 0; i < mylist.size(); i++) {
long startepoch = getTime(mylist.get(i).time);
MyItem m = mylist.get(i);
String index=(i+1)+"";
future1 = executorService.submit(new Callable() {...})
//adds to hashmap1
future1.get(); // Add this if you need to wait for process1 to finish before moving on to others. Also, add a try{}catch{} block as shown below.
if(m.name.equals("TEST")) {
future2 = executorService.submit(new Callable() {...})
//adds to hashmap2
future2.get(); // Add this if you need to wait for process2 to finish before moving on to others. Also, add a try{}catch{} block as shown below.
} else {
future3 = executorService.submit(new Callable() {...})
//adds to hashmap3
future4 = executorService.submit(new Callable() {...})
//adds to hashmap4
future5 = executorService.submit(new Callable() {...})
//adds to hashmap5
future6 = executorService.submit(new Callable() {...})
//adds to hashmap6
// Add extra future.get here as above...
}
}
// then start calculation on all hashmaps
calculate_all();
Don't forget to add a try-catch block, otherwise you may not recover from exceptions and crash.
// Example try-catch block surrounding a Future.get().
try {
Object result = future.get();
} catch (ExecutionException e) {
//Do something
} catch (InterruptedException e) {
//Do something
}
However, you can have a more complex one as shown here. That link also explains Thilo's answer.