Multithreading not working - Create thread per loop index Java

I wrote the below code trying to run two threads for calling a function in a for loop, but the results have the same time as if I ran it sequentially without multiple threads. Any thoughts why the multithreading here is not working? Is there a better way to do it? Like for example if I wanted to have 10 threads, using my code this will mean I have to create 10 duplicate run() functions when creating the thread, I wonder if there is an easier way to set the number of threads? Also is it possible to create a number of threads depending on the loop counter so that each loop a thread is created to finish it so if I had 10 loops then 10 threads will run concurrently to finish the processing very fast?

   private Thread t1 = new Thread(){
   public void run(){

            for (int i = 0; i < 2; i++)
            {
                try {
                    myfn(i);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    };

    private Thread t2 = new Thread(){
        public void run(){

            for (int i = 2; i < 4; i++)
            {
                try {
                    myfn(i);
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            }
    };

 public Results getResults() throws IOException, SocketTimeoutException {

        t1.start();
        t2.start();
        try {
            t1.join(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

4 answers

  • answered 2017-11-14 23:37 Olivier Grégoire

    You don't need to copy your threads / loop 10 times, just take the logic and use it appropriately.

    public class ExampleThread extends Thread {
      private final int start, iterations;
      public ExampleThread(int start, int iterations) {
        this.start = start;
        this.iterations = iterations;
      }
      @Override public void run() {
        for (int i = 0; i < iterations; i++) {
          myfn(start + i);
        }
      }
    }
    
    int iterations = 2;
    List<Thread> threads = new ArrayList<>();
    for (int threadId = 0; threadId < 10; threadId++) {
      threads.add(new ExampleThread(threadId * iterations, iterations));
    }
    threads.forEach(Thread::start);
    threads.forEach(t -> {
      try {
        t.join(0);
      } catch (Exception e) {
        e.printStackTrace(System.err);
      }
    });
    

  • answered 2017-11-14 23:37 Alex Taylor

    For running the same task across multiple threads, you're probably looking for a thread pool. Java provides a ThreadPoolExecutor for this.

    Here is an introduction to Java concurrency with the following example:

    ExecutorService executor = Executors.newFixedThreadPool(1);
    
    Future<Integer> future = executor.submit(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
            return 123;
        }
        catch (InterruptedException e) {
            throw new IllegalStateException("task interrupted", e);
        }
    });
    
    future.get(1, TimeUnit.SECONDS);
    

    That example specifically creates a pool with only a single thread, but the parameter to Executors.newFixedThreadPool controls how many threads will be used.

    I'm not sure from your original question why you think two threads aren't being utilized.

  • answered 2017-11-14 23:38 haifzhan

    public class MyThead extend Thread{
        private int initValue = 0;
        private int upperBound = 0;
    
        public MyThread(int init, int ub){
            this.initValue = init;
            this.upperBound = ub;
        }
        public void run(){
            for(int i = init; i < upperBound; i++){
                myfn(i);
            }
        }
    }
    

    Create threads and start them:

    List<Thread> threads = new ArrayList<>();
    threads.add(new MyThread(0,2));
    threads.add(new MyThread(2,4));
    
    for(Thread t: threads){
        t.start()
    }
    
    for(Thread t: threads){
        t.join();
    }
    

  • answered 2017-11-15 15:49 Gray

    I wrote the below code trying to run two threads for calling a function in a for loop, but the results have the same time as if I ran it sequentially without multiple threads.

    There are many reasons why that can happen although it's hard to know what is going on without seeing the myfn(...) code. Here are some possible reasons:

    • It could be that myfn runs so quickly that running it in different threads isn't going to be any faster.
    • It could be that myfn is waiting on some other resource in which case the threads can't really run concurrently.
    • It could be that myfn is blocking on IO (network or disk) and even though you are doing 2 (or more) of them at a time, the disk or the remote server can't handle the increased requests any faster.

    Is there a better way to do it? Like for example if I wanted to have 10 threads, using my code this will mean I have to create 10 duplicate run() functions...

    The right thing to do here is to create your own class which takes the lower and upper bounds. The right way to do this is to implement Runnable, not extend Thread. Something like:

    public class MyRunnable implements Runnable {
        private final int start;
        private final int end;
        public MyRunnable(int start, int end) {
            this.start = start;
            this.end = end;
        }
        public void run() {
            for (int i = start; i < end; i++) {
                myfn(i);
            }
        }
    }
    

    You can then either start the threads by hand or use an ExecutorService which makes the thread maintenance a lot easier:

    // this will start a new thread for every job
    ExecutorService threadPool = Executors.newCachedThreadPool();
    threadPool.submit(new MyRunnable(0, 2));
    threadPool.submit(new MyRunnable(2, 4));
    // once you've submitted your last task, you shutdown the pool
    threadPool.shutdown();
    // then we wait until all of the tasks have run
    threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);