-1

So i need to process a couple data files using threads (already splitted), and i'm having issues on how to stop the main thread till all the subthreads finish. i looked around and tried to use join() but this causes an issue:

  • If i join the main thread with the last thread then since the other threads run at the same time, the last thread is not always the last one to finish
  • If i join the main thread with all the other threads then they don't run at the same time, the second needs the first to finish first. also tried wait() and notify() but had even more issues. here's a part of my code

        public class Matrix extends MapReduce {
        ArrayList<String> VecteurLines = new ArrayList<String>();
        protected int[] nbrLnCol = {0,0};
        protected static double[] res;

        public Matrix(String n) {
            super(n);
        }
        public Matrix(String n,String m){
            super(n,m);
        }
    public void Reduce() throws IOException, InterruptedException, MatrixException {

            for (int i = 1; i <= Chunks; i++) {

                Thread t=new Thread(new RunThread(VecteurLines,i,this));
                t.start();

            }
        }

And here's the class that handles the threads


    public class RunThread extends Matrix implements Runnable {
            Matrix ma;
            ArrayList<String> vec;
            int threadNbr;


            public RunThread(ArrayList<String> vec, int threadNbr,Matrix ma)  {
                super("","");
                this.vec=vec;this.threadNbr=threadNbr;this.ma=ma; }

            @Override
            public void run() {

                FileInputStream fin = null;
                try {
                    fin = new FileInputStream(ma.getNom()+threadNbr+".txt");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                Scanner sc = new Scanner(fin);


                while (sc.hasNext()) {
                    String nextString = sc.next();

                    ma.nbrLnCol[0]++;
                    String [] arr = nextString.split(",");
                    ma.nbrLnCol[1]=arr.length;
                    double c=0;
                    for(int j=0;j<arr.length;j++)
                    {
                        c+=(Double.parseDouble(arr[j])*Double.parseDouble(vec.get(j)));

                    }

                    res[threadNbr-1]=c;
                }
                sc.close();
                try {
                    fin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                File file = new File(ma.getNom()+threadNbr+".txt");
                file.delete();
            }

  • 1
    the evident solution is to join all the subthreads, but I cannot see join() in your code. – Alexei Kaigorodov Jan 13 '20 at 23:38
  • i removed it because it ended up running threads one by one and not all of them simultaneously – Ayman Elya Jan 13 '20 at 23:45
  • 1
    `join` should not cause any of the threads to be delayed. What exactly did you try? And what is happening in the main thread? It looks like `RunThread` performs some operations in each thread, but none of the code you've provided does any thread management besides starting a series of threads. – jirassimok Jan 14 '20 at 00:13
  • 1
    @Ayman Elya join() does not make threads to run one by one. There was different reason for that. – Alexei Kaigorodov Jan 14 '20 at 00:13
  • well i added t.join() right after t.start() but when testing it seems like it goes like this: startthread1-->endthread1-->startthread2-->endthread2 and so on while it should be startthread1-->startthread2 etc. then after those threads are done, the main one resumes – Ayman Elya Jan 14 '20 at 00:40
  • 1
    So that code, there's a bug in it but we can't fix it until we have the code. – markspace Jan 14 '20 at 00:57

2 Answers2

0

Try like this:

 private List<Thread> threadList = new ArrayList<>();

 public void Reduce() {
     threadList.clear();
     for (int i = 1; i <= Chunks; i++) {
         Thread t  =new Thread(new RunThread(VecteurLines,i,this));
         threadList.add(t);
     }

     // start all worker threads
     for(int i=0; i<threadList.size(); i++){
         threadList.get(i).start();
     }

     // wait until all worker threads is finished
     while (true) {
         int threadIsNotLive = 0;
         for (int i = 0; i < threadList.size(); i++) {
             Thread t = threadList.get(i);
             if (!t.isAlive() || t == null) {
                 ++threadIsNotLive;
             }
         }
         if(threadIsNotLive>0 && (threadList.size() == threadIsNotLive)){
             break;
             // all worker threads is finished
         }
         else {
             Thread.sleep(50);
             // wait until all worker threads is finished
         }
     }
 }

OR

 public void Reduce() {
     List<Thread> threadList = new ArrayList<>();
     for (int i = 1; i <= Chunks; i++) {
         Thread t  =new Thread(new RunThread(VecteurLines,i,this));
         threadList.add(t);
     }

     // start all worker threads
     for(int i=0; i<threadList.size(); i++){
         threadList.get(i).start();
         threadList.get(i).join();
     }
 }
koding
  • 155
  • 1
  • 9
  • Storing all `Thread` instances into a list is the right approach, to ensure all have been started before the main thread begins waiting. However, there is no point in doing that complicated last loop. A simple `for(Thread t: threadList) t.join();` would do. And instead of storing the list into a field, needing to `clear()` it, just declare `List threadList = new ArrayList<>();` as the first statement in the method, to make it a local variable. – Holger Jan 16 '20 at 18:46
  • No, with that code, you reintroduced the problem, waiting for each thread right after starting it makes the execution serial. You need one loop to start all threads, then another loop to wait for them. And don’t hesitate to use the for-each loop, `for(Thread t: threadList) …` instead of an index loop. – Holger Jan 17 '20 at 08:35
0

I believe you need two points in your code: Your main thread has to end last after all the thread's executed because you said

"how to stop the main thread till all the subthreads finish"

. Second ,the thread should finish one after another that is the 2nd thread should finish after 1st thread as you said

"the second needs the first to finish first."

Here is my code to do it with join .

public class Matrix extends MapReduce {
    ArrayList<String> VecteurLines = new ArrayList<String>();
    protected int[] nbrLnCol = {0,0};
    protected static double[] res;

    public Matrix(String n) {
        super(n);
    }
    public Matrix(String n,String m){
        super(n,m);
    }
public void Reduce() throws IOException, InterruptedException, MatrixException {
    Thread t = null;
        for (int i = 1; i <= Chunks; i++) {

            Thread t=new Thread(new RunThread(t,VecteurLines,i,this));
            t.start();

        }
      t.join(); // finally main thread joining with the last thread.
    }

and

public class RunThread extends Matrix implements Runnable {
        Matrix ma;
        ArrayList<String> vec;
        int threadNbr;
        Thread t;


        public RunThread(t,ArrayList<String> vec, int threadNbr,Matrix ma)  {
            this.t = t;
            super("","");
            this.vec=vec;this.threadNbr=threadNbr;this.ma=ma; }

        @Override
        public void run() {                
            FileInputStream fin = null;
            try {
                fin = new FileInputStream(ma.getNom()+threadNbr+".txt");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            Scanner sc = new Scanner(fin);


            while (sc.hasNext()) {
                String nextString = sc.next();

                ma.nbrLnCol[0]++;
                String [] arr = nextString.split(",");
                ma.nbrLnCol[1]=arr.length;
                double c=0;
                for(int j=0;j<arr.length;j++)
                {
                    c+=(Double.parseDouble(arr[j])*Double.parseDouble(vec.get(j)));

                }

                res[threadNbr-1]=c;
            }
            sc.close();
            try {
                fin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            File file = new File(ma.getNom()+threadNbr+".txt");
            file.delete();
            if(t!=null){
             t.join(); //join with the previous thread eg. thread2 joining with thread1
            }
        }
xpioneer
  • 3,075
  • 2
  • 16
  • 18