如何等待函数完成(线程中的线程)

时间:2019-12-25 23:37:29

标签: java multithreading

我认为我对Threads有点迷茫,因为我不明白为什么它不起作用...

我有一个包含服务器客户端和节点的程序。 客户端将分组数据(GroupedDataFrame)发送到服务器,要求计算例如平均。服务器将该任务分配给其节点,节点将对其进行计算并将其结果返回给服务器。

我的问题是,当我使用applyWithThreads时,NODE返回一个空的DataFrame (没有计算结果)(如果我使用普通的“ apply”(没有线程),那么它工作正常 >)。

据我所知,创建NodeResult的命令不会等待上一个函数完成,即applywithThreads ,因此,它会发送空的DF(因为如果我设置了等待时间,例如2秒它的工作:/,或者如果我使用此注释循环,但我知道这是不好的做法)

我想以某种方式解决它!如何等待applythread完成(将形成returnToServer)?

    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();
                }
            }
        }
    }

这是applyWithThreads的代码:

    public DataFrame applyWithThreads(Applyable fun) {
        DataFrame ret = new DataFrame();
        ArrayList<DataFrameThread> threadList = new ArrayList<>();
        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;
    }

和DataFrameThread的代码:

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);
        }
    }
}

``

1 个答案:

答案 0 :(得分:1)

您的代码有很多问题。我会尝试越过它们。

关键的:

  • 您的DataFrameThread扩展了Thread,但是,如果您像使用ExecutorService那样使用线程池,则不再由您创建线程。不用说extends Thread,而是说implements Runnable
  • 在ExecutorService上调用shutdown()不会等待它停止。您可以在致电awaitTermination之后致电shutdown,但这不是您应该使用ExecutorService的方式。
  • 一种改进是使用submit而不是executesubmit返回Future<?>,您可以在get()上调用Future,它将阻塞直到完成。
  • 更好的是,代替实现Runnable,而实现CallableCallable用于返回值的任务。您无需从ret.addAnotherDF中调用Runnable,而是从可调用对象返回DataFrame。然后,submit将返回一个Future<DataFrame>,并且当您在其上调用get时,它会在线程完成后返回DataFrame对象。
  • 注意:仅在将所有任务提交到get时调用Future上的ExecutorService,而不是在每个任务之后都进行调用(如果您在每个任务之后都执行,则不会再并行化问题)

重要:

  • 不要为每个applyWithThreads调用创建一个新的ExecutorService。线程池的关键是尽可能长时间地保持线程池,因为创建线程是一项昂贵的操作。这就是为什么您不应该使用shutdownawaitTermination来确定任务何时完成的原因;这就是为什么您可以使用Future个对象这样做的原因。