title: How to wait for the function finish (Threads in Thread)
body: <p>I think I'm a little lost in Threads because I don't understand why it's not working...</p>
  
  <p>I have a program that has Server Clients and Nodes. 
  The client sends grouped data (GroupedDataFrame) to the server asking for calculation of e.g. averages. The server distributes this task to its Nodes which calculate it and return their results to Server.</p>
  
  <p><strong>My problem is that NODE returns an empty DataFrame</strong> (without calculated results) when I use applyWithThreads (<strong>if I use normal "apply" (without threads) it is working good</strong>).</p>
  
  <p>From what I realized, <strong>the command to create NodeResult does not wait for the previous function to finish i.e. applywithThreads</strong>, as a result, it sends empty DF (because if I set waiting for example 2 sec its working :/, or if I use this commented out loop, but I know it is bad practice)</p>
  
  <p><strong>I would like to solve it somehow! How to wait for applythread to finish (will form returnToServer)?</strong></p>
  
  <pre><code>    class ListenFromServer extends Thread {
          public void run() {
              while (true) {
                  try {
                      Object obj = sInput.readObject();
                      if (obj instanceof String) {
                          display((String) obj);
                      } else if (obj instanceof NodeRequestGDF) {
                          display("I have received NodeRequest from client ID: " + ((NodeRequestGDF) obj).getClientID());
  
  
                          // DataFrame returnToServer = (((NodeRequestGDF) obj).groupedDF.apply(((NodeRequestGDF) obj).getFunction()));  
                          DataFrame returnToServer = (((NodeRequestGDF) obj).groupedDF.applywithThreads(((NodeRequestGDF) obj).getFunction()));
                          // while (returnToServer.size() != (((NodeRequestGDF) obj).getGroupedDF().getSize()));
  
  
                          NodeResultDF nodeResultDF = new NodeResultDF(returnToServer, ((NodeRequestGDF) obj).getClientID());
                          sendToServer(nodeResultDF);
                          display("I have returned result to Server to client ID: " + nodeResultDF.clientID);
  
                      } else {
                          display("I have received something i do not know what is this :(");
                      }
                  } catch (IOException e) {
                      display("Server has close the connection: " + e);
                  } catch (ClassNotFoundException e2) {
                      e2.printStackTrace();
                  }
              }
          }
      }
  </code></pre>
  
  <p>Here is code of applyWithThreads:</p>
  
  <pre><code>    public DataFrame applyWithThreads(Applyable fun) {
          DataFrame ret = new DataFrame();
          ArrayList&lt;DataFrameThread&gt; threadList = new ArrayList&lt;&gt;();
          for (DataFrame df : this.data) {
              DataFrameThread tmp = new DataFrameThread(df, fun, ret);
              threadList.add(tmp);
          }
          ExecutorService threadPool = Executors.newFixedThreadPool(MAX_Threads);
          for (DataFrameThread th : threadList) {
              threadPool.execute(th);
          }
          threadPool.shutdown();
          return ret;
      }
  </code></pre>
  
  <p>and code of DataFrameThread:</p>
  
  <pre><code>import GroupFunctions.Applyable;
  
  public class DataFrameThread extends Thread {
      DataFrame ret;
      DataFrame DF;
      Applyable fun;
  
      public DataFrameThread(DataFrame df, Applyable fun, DataFrame ret) {
          this.DF = df;
          this.fun = fun;
          this.ret = ret;
      }
  
      @Override
      public void run() {
          DataFrame d = null;
          try {
              d = fun.apply(DF);
          } catch (InconsistentTypeException e) {
              e.printStackTrace();
          }
          synchronized (ret) {
              ret.addAnotherDF(d);
          }
      }
  }
  
  ``
  </code></pre>