0

I have a process method in two of my classes which accepts a Map of String.

In the below code, I am using a for loop which will call the process method in two of my classes one by one (sequentially) which is fine.

for (ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
    final Map<String, String> response = entry.getPlugin().process(outputs);

    System.out.println(response);
}

But is there any way I can launch two thread for this? One thread will call process method of one of my class and second thread will call process method in my second class? And then after getting response from each thread, I want to write to the database. meaning each thread will write to database.

And also there should be timeout feature as well for each thread. We will wait for each thread a specified amount of time, meaning if one of the process method is not returned withing a certain time, then it will get timedout.

Is this possible to do in my use case? If yes, can anyone provide me an example of how to do this? Thanks.

Any help will be appreciated on this.

AKIWEB
  • 19,008
  • 67
  • 180
  • 294

1 Answers1

2

You can create an ExecutorService with however many threads allocated as you want running, e.g.

ExecutorService executor = Executors.newFixedThreadPool(2)

Now inside of your for loop you would do something like

for (ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
    executor.submit(new Runnable () {
        public void run() {
            final Map<String, String> response = entry.getPlugin().process(outputs);
            // write to database
            System.out.println(response);
        }
    }
}

You may also want to have a separate thread handling all of the database writes - your runnables would send their results to it via a BlockingQueue or something along those lines

// Three threads: one thread for the database writer, two threads for the plugin processors
final ExecutorService executor = Executors.newFixedThreadPool(3);

final BlockingQueue<Map<String, String>> queue = new LikedBlockingQueue<>();

Future future = executor.submit(new Runnable () {
    public void run() {
        Map<String, String> map;
        try {
            while(true) {
                // blocks until a map is available in the queue, or until interrupted
                map = queue.take();
                // write map to database
            }
        } catch (InterruptedException ex) {
            // IF we're catching InterruptedException then this means that future.cancel(true)
            // was called, which means that the plugin processors are finished;
            // process the rest of the queue and then exit
            while((map = queue.poll()) != null) {
                // write map to database
            }
        }
    }
}

for (ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
    executor.submit(new Runnable () {
        public void run() {
            final Map<String, String> response = entry.getPlugin().process(outputs);
            // put the response map in the queue for the database to read
            queue.offer(response);
        }
    }
}

// this interrupts the database thread, which sends it into its catch block
// where it processes the rest of the queue and exits
future.cancel(true); // interrupt database thread

// wait for the threads to finish
executor.awaitTermination(5, TimeUnit.MINUTES);
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • Thanks a lot Zim-Zam for the suggestion. When I copied the whole exact code in eclipse. I saw one compilation issues on the semicolon on this line `Map map;` I am not sure how to fix that.. And also can you please add some description for my better understanding as well? It will help me a lot.. Thanks for the help.. – AKIWEB Aug 22 '13 at 02:56
  • @TrekkieTechie T-T I've added some comments and fixed the compilation error. The idea is that you're creating a lot of anonymous Runnables that you send to the ExecutorService, which you're initializing to three threads (one for the database writer, two for the plugin processors); you can increase this to the number of hardware threads (which is the number of cores, times two if you have hyperthreading) plus one (since the database thread is IO bound). When the plugin processing threads are finished you interrupt the database processing thread so that it will eventually terminate. – Zim-Zam O'Pootertoot Aug 22 '13 at 03:09
  • One last thing I forgot to ask is what is the use of the last line here? `executor.awaitTermination(5, TimeUnit.MINUTES);`.. – AKIWEB Aug 22 '13 at 05:40
  • @TrekkieTechie T-T That waits five minutes for all of the threads to exit - at that point the plugin processor threads should have already exited, so you can replace this line with `future.get()` which will wait for the database thread to exit. – Zim-Zam O'Pootertoot Aug 22 '13 at 13:36
  • I know this post is old and got closed. Somehow this code is not running. If I remove the last `awaitTermination` line then it always run fine but after some time, I always get error like this- `JVMDUMP006I Processing dump event "systhrow", detail "java/lang/OutOfMemoryError" - please wait.`. But If I keep that line, it never runs. Any idea why it is happening? – AKIWEB Aug 27 '13 at 22:53
  • I have open a new question for this. here is the [question](http://stackoverflow.com/questions/18475772/how-to-call-same-method-of-a-different-class-in-multithreaded-way). Any helo will be appreciated on this.. – AKIWEB Aug 28 '13 at 06:13