Java 获取线程的输出

Java 获取线程的输出,java,multithreading,Java,Multithreading,您认为获得线程工作结果的最佳方法是什么?想象一个线程进行一些计算,你如何警告主程序计算已经完成 您可以每隔X毫秒轮询一个名为“job finished”的公共变量或其他内容,但随后您将收到比可用时更晚的结果。。。主代码将失去等待它们的时间。另一方面,如果使用较低的X,CPU将浪费大量轮询时间 那么,您如何才能意识到线程或某些线程已经完成了它们的工作呢 很抱歉,如果它看起来与另一个相似,我想这可能就是埃本回答的原因。我的意思是运行很多线程,并且知道它们什么时候都完成了,而不用轮询它们 我想的更多的

您认为获得线程工作结果的最佳方法是什么?想象一个线程进行一些计算,你如何警告主程序计算已经完成

您可以每隔X毫秒轮询一个名为“job finished”的公共变量或其他内容,但随后您将收到比可用时更晚的结果。。。主代码将失去等待它们的时间。另一方面,如果使用较低的X,CPU将浪费大量轮询时间

那么,您如何才能意识到线程或某些线程已经完成了它们的工作呢

很抱歉,如果它看起来与另一个相似,我想这可能就是埃本回答的原因。我的意思是运行很多线程,并且知道它们什么时候都完成了,而不用轮询它们

我想的更多的是在使用线程批的多个CPU之间共享CPU负载,并知道批何时完成。我想它可以通过Futures对象来实现,但是阻塞get方法看起来很像一个隐藏的锁,而不是我喜欢的东西


谢谢大家的支持。虽然我也喜欢erickson的答案,但我认为saua是最完整的,也是我将在自己的代码中使用的。

不要使用线程之类的低级构造,除非您绝对需要强大的功能和灵活性

您可以使用诸如to之类的。这将返回一个对象

使用这个
Future
对象,您可以轻松地检查它是否已完成并获得结果(如果尚未完成,则包括阻塞
get()

这些构造将大大简化最常见的线程操作

我想澄清一下阻塞
get()

这样做的想法是,您希望运行一些任务(可调用的
s),这些任务执行一些您现在不需要结果的工作(计算、资源访问等)。您可以依靠
执行器
随时运行代码(如果它是
线程池执行器
,那么它将在空闲线程可用时运行)。然后在某个时间点,您可能需要计算结果才能继续。此时,您应该调用
get()
。如果任务已在该点运行,则
get()
将立即返回该值。如果任务未完成,则
get()
调用将等待任务完成。这通常是需要的,因为没有任务结果,您无法继续


当您不需要继续使用该值,但想知道它是否已经可用(可能在UI中显示某些内容)时,您可以轻松调用
isDone()
,并且仅在返回
true
)时调用
get()

轮询a.k.忙着等待不是一个好主意。正如您所提到的,繁忙的等待会浪费CPU周期,并可能导致应用程序看起来没有响应

我的Java很粗糙,但您需要以下内容:

如果一个线程必须等待另一个线程的输出,则应使用条件变量

final Lock lock = new ReentrantLock();
final Condition cv = lock.newCondition();

对其他威胁的输出感兴趣的线程应该调用
cv.wait()
。这将导致当前线程阻塞。工作线程完成工作后,应调用
cv.signal()
。这将导致阻塞的线程解除阻塞,从而允许它检查工作线程的输出。

如saua所述:使用java.util.concurrent提供的构造。如果您坚持使用1.5(或5.0)版本之前的JRE,您可能会求助于自己的JRE,但您最好使用一个后端口:

作为Saua所描述的并发API的替代方案(如果主线程不需要知道工作线程何时完成),您可以使用发布/订阅模式


在这个场景中,子
线程
/
可运行
被赋予一个监听器,该监听器知道如何处理结果,并在子
线程
/
可运行
完成时被调用。

您的场景仍然有点不清楚

如果正在运行批处理作业,则可能需要使用。这将阻止主线程,直到所有任务完成。这种方法没有“忙等待”,主线程将浪费CPU轮询未来的
isDone
方法。虽然此方法返回一个
未来的列表
,但它们已经“完成”。(还有一个重载版本可以在完成之前超时,这可能更安全地用于某些任务。)这比尝试自己收集一堆未来的对象并尝试单独检查它们的状态或阻止它们的get方法要干净得多

如果这是一个交互式应用程序,任务偶尔会在后台执行,那么使用所建议的方法是一个很好的方法。在这里,使用a
Runnable
run
方法在计算回调结果时调用回调。使用这种方法,您可以放弃
提交
返回的
未来
,除非您希望能够
取消
正在运行的任务而不关闭整个
执行服务


如果您希望能够取消任务或使用超时功能,那么需要记住的一点是,通过调用线程来取消任务。因此,您的任务需要定期检查并根据需要中止。

子类线程,并为您的类提供一个返回结果的方法。调用该方法时,如果结果尚未创建,则使用线程join()。当join()返回时,线程的工作将完成,结果应该可用;归还它

仅当您实际需要f时才使用此选项
/**
 * Listener interface to implement to be called when work has
 * finished.
 */
public interface WorkerListener {
    public void workDone(WorkerThread thread);
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Thread to perform work
 */
public class WorkerThread implements Runnable {
    private List listeners = new ArrayList();
    private List results;

    public void run() {
        // Do some long running work here

        try {
            // Sleep to simulate long running task
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        results = new ArrayList();
        results.add("Result 1");

        // Work done, notify listeners
        notifyListeners();
    }

    private void notifyListeners() {
        for (Iterator iter = listeners.iterator(); iter.hasNext();) {
            WorkerListener listener = (WorkerListener) iter.next();
            listener.workDone(this);
        }
    }

    public void registerWorkerListener(WorkerListener listener) {
        listeners.add(listener);
    }

    public List getResults() {
        return results;
    }
}
import java.util.Iterator;
import java.util.List;

/**
 * Class to simulate a main program
 */
public class MainProg {
    public MainProg() {
        WorkerThread worker = new WorkerThread();
        // Register anonymous listener class
        worker.registerWorkerListener(new WorkerListener() {
            public void workDone(WorkerThread thread) {
                System.out.println("Work done");
                List results = thread.getResults();
                for (Iterator iter = results.iterator(); iter.hasNext();) {
                    String result = (String) iter.next();
                    System.out.println(result);
                }
            }
        });

        // Start the worker thread
        Thread thread = new Thread(worker);
        thread.start();

        System.out.println("Main program started");
    }

    public static void main(String[] args) {
        MainProg prog = new MainProg();
    }
}