A_Elric
A_Elric

Reputation: 3568

Multithreaded Programming in java, best practices and code

I'm writing a file that does a HUGE number of calls to different locations online (sadly that's part of a requirement)

My question is something like this:

Let's assume that I have a main method and want to call some other method:

public static void main(String args[]){
    //how do I break stuff into threads here
     Thread nameThread1 = new(fileName.DoMethod1(x))
     Thread nameThread2 = new(fileName.DoMethod2(x))
     Thread nameThread3 = new(fileName.DoMethod3(x))
     Thread nameThread4 = new(fileName.DoMethod4(x))
     Thread nameThread5 = new(fileName.DoMethod5(x))
}



           //fileName.java
public static void doMethod1(object){
   //Do Method Stuff
}

public static void doMethod2(object){
   //Do Method Stuff
}

I've read some guides about how to implement it, but I'm still confused about the precise way to do this.

Can someone show me some examples if possible? Thanks!

Upvotes: 0

Views: 3383

Answers (4)

yadab
yadab

Reputation: 2143

well, A lot of people suggested you to use Runnable but I would suggest you to use callable because Runnable, does not return a result and cannot throw a checked exception. To organize the code better and able to throw exceptions or return value from method use callable. Also for your purpose use some pool executor to do the job. Here is how I would say about the design, -

  1. Write a callable class and based on request params call appropriate method,

    private class GetAndProcessResponse implements Callable { private final Request request; private final CountDownLatch countDownLatch;

        GetAndProcessResponse(final Request request, final CountDownLatch countDownLatch) {
            this.request = request;
            this.countDownLatch = countDownLatch;
        }
    
        public ProcessedResponse call() {
            try {
                // do a switch case on request params
                // and call appropriate methods.
            } finally {
                countDownLatch.countDown();
            }
        }
    }
    
  2. Use countDownLatch to get job completion status.

  3. Do not call join, since you need use executor service.

  4. Use future.get(timeout) since it is a network job and need to cut after some time.

Upvotes: 0

loscuropresagio
loscuropresagio

Reputation: 1952

If you have to do a huge number of calls, the best solution is to instantiate a thread pool and use it for all your tasks. Later, you coild tune it depending on number of processors/cores your machine has. Here's a quite straightforward impementation using a ThreadPoolExecutor:

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class GenericThreadPool {

    private static final int CORE_POOL_SIZE = 3;
    private static final int MAXIMUM_POOL_SIZE = 10;
    private static final long KEEP_ALIVE_TIME = 10;

    private ThreadPoolExecutor threadPool = null;
    private final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();

    private GenericThreadPool() {
        this.threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
                this.queue);

    }

    private static class LazyHolder {
        public static final GenericThreadPool INSTANCE = new GenericThreadPool();
    }

    public static GenericThreadPool getInstance() {
        return LazyHolder.INSTANCE;
    }

    public void execute(Runnable task) {
        this.threadPool.execute(task);
    }

    public void shutdown() {
        this.threadPool.shutdown();
    }


}

To execute a task you just make a class that implements Runnable interface, get the threadpool instance and run your job.

public class MyJob implements Runnable {
   public void run(){
      // Do your job here...
   }
}

GenericThreadPool pool = GenericThreadPool.getInstance();
pool.execute(new MyJob());

Upvotes: 1

Gray
Gray

Reputation: 116858

You cannot call different methods like in your post. What you can do is to call different classes:

public static void main(String args[]){
     Thread nameThread1 = new Thread(new Method1(x));
     nameThread1.start();
     Thread nameThread2 = new Thread(new Method2(x));
     nameThread2.start();
     Thread nameThread3 = new Thread(new Method3(x));
     nameThread3.start();
     Thread nameThread4 = new Thread(new Method4(x));
     nameThread4.start();
     Thread nameThread5 = new Thread(new Method5(x));
     nameThread5.start();
}

public class Method1 implements Runnable {
   private Object obj;
   public Method1(Object obj) {
       this.obj = obj;
   }
   //fileName.java
   public void run(){
      //Do Method Stuff
   }
}

You should always consider using the create ExecutorService code to manage jobs like this. For example:

// create a thread pool with 10 workers
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(new Method1(x));
threadPool.submit(new Method2(x));
...
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();

If you must use one class then you could start a single Runnable that uses a switch or something:

public static void main(String args[]){
     Thread nameThread1 = new Thread(new Method(1, x));
     nameThread1.start();
     Thread nameThread2 = new Thread(new Method(2, x));
     nameThread2.start();
     ...
}
public class Method1 implements Runnable {
   private int which;
   private Object obj;
   public Method1(int which, Object obj) {
       this.which = which;
       this.obj = obj;
   }
   //fileName.java
   public void run(){
       switch(which) {
          case 1:
             doMethod1(obj);
             break;
          case 2:
             doMethod2(obj);
             break;
          ...
       }
    }
    private void doMethod1(Object obj){
       ...
    }
    private void doMethod2(Object obj){
       ...
    }
}

But the executors or the separate Runnable classes would be cleaner.

Upvotes: 8

mprabhat
mprabhat

Reputation: 20323

Thread needs an instance of Runnable, so what you can do is create a class which implements Runnable and you pass the command that it has to respond to, then depending upon the command you choose which method to call.

public class MyRunnable implements Runnable {

   public MyRunnable(String commandToExecute){
      this.command = commandToExecute;
   }

   public void run() {
      //depending on command call specific methods.
   }
}

One disadvantage of this approach is that your run method has too long a list of if else to check which method to invoke.

Benefit is that you don't create unnecessary class if all the methods are related to one class and placing them in separate classes doesn't make sense.

Another approach is to have separate class for every method as suggested by Gray, instead of you directly creating instance of specific class you can use Factory Pattern to create and instance for you.

Upvotes: 1

Related Questions