java 获取线程的输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/352638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:02:47  来源:igfitidea点击:

Getting the output of a Thread

javamultithreading

提问by Saiyine

What do you think is the best way for obtaining the results of the work of a thread? Imagine a Thread wich does some calculations, how do you warn the main program the calculations are done?

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

You could poll every X milliseconds for some public variable called "job finished" or something by the way, but then you'll receive the results later than when they would be avaliable... the main code would be losing time waiting for them. On the other hand, if you use a lower X, the CPU would be wasted polling so many times.

您可以每 X 毫秒轮询一次名为“作业完成”的公共变量或顺便说一句,但是随后您将收到结果,而不是它们可用的时间……主要代码将浪费时间等待它们。另一方面,如果您使用较低的 X,则 CPU 将浪费多次轮询。

So, what do you do to be aware that the Thread, or some Threads, have finished their work?

那么,你怎么做才能知道 Thread 或一些 Threads 已经完成了它们的工作?

Sorry if it looks similar to this other question, that's probably the reason for the ebenanswer, I suppose. What I meaned was running lots of threads and know when all of them have finished, without polling them.

对不起,如果它看起来与另一个问题相似,我想这可能是eben答案的原因。我的意思是运行大量线程并知道它们何时完成,而无需轮询它们。

I was thinking more in the line of sharing the CPU load between multiple CPU's using batches of Threads, and know when a batch has finished. I suppose it can be done with Futures objects, but that blocking getmethod looks a lot like a hidden lock, not something I like.

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

Thanks everybody for your support. Althought I also liked the answer by erickson, I think saua's the most complete, and the one I'll use in my own code.

谢谢大家的支持。Althought我也喜欢通过回答埃里克森,我觉得SAUA的最完整的,和一个我会在自己的代码中使用。

回答by Joachim Sauer

Don't use low-level constructs such as threads, unless you absolutely need the power and flexibility.

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

You can use a ExecutorServicesuch as the ThreadPoolExecutorto submit()Callables. This will return a Futureobject.

您可以使用ExecutorService(例如ThreadPoolExecutor)submit() Callables。这将返回一个Future对象。

Using that Futureobject you can easily check if it's done and get the result (including a blocking get()if it's not yet done).

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

Those constructs will greatly simplify the most common threaded operations.

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

I'd like to clarify about the blocking get():

我想澄清一下阻塞get()

The idea is that you want to run some tasks (the Callables) that do some work (calculation, resource access, ...) where you don't need the result right now. You can just depend on the Executorto run your code whenever it wants (if it's a ThreadPoolExecutorthen it will run whenever a free Thread is available). Then at some point in time you probably needthe result of the calculation to continue. At this point you're supposed to call get(). If the task already ran at that point, then get()will just return the value immediately. If the task didn't complete, then the get()call will wait until the task is completed. This is usually desired since you can't continue without the tasks result anyway.

这个想法是,要运行一些任务(在Callable那做了一些工作(计算,资源访问,...),您不需要结果S)现在。您可以依赖Executor随时运行您的代码(如果它是,ThreadPoolExecutor那么只要有空闲线程可用,它就会运行)。然后在某个时间点,您可能需要计算结果才能继续。此时你应该调用get(). 如果此时任务已经运行,则将get()立即返回该值。如果任务没有完成,则get()调用将等到任务完成。这通常是需要的,因为无论如何您都无法在没有任务结果的情况下继续。

When you don't need the value to continue, but would like to know about it if it's already available (possibly to show something in the UI), then you can easily call isDone()and only call get()if that returns true).

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

回答by Neal Donnan

You could create a lister interface that the main program implements wich is called by the worker once it has finished executing it's work.

您可以创建一个主程序实现的列表器接口,一旦它完成工作,它就会被工作人员调用。

That way you do not need to poll at all.

这样你根本不需要轮询。

Here is an example interface:

这是一个示例界面:

/**
 * Listener interface to implement to be called when work has
 * finished.
 */
public interface WorkerListener {
    public void workDone(WorkerThread thread);
}

Here is an example of the actual thread which does some work and notifies it's listeners:

下面是一个实际线程的例子,它做一些工作并通知它的听众:

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

And finally, the main program which starts up a worker thread and registers a listener to be notified once the work is done:

最后,主程序启动一个工作线程并注册一个监听器以在工作完成后得到通知:

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

回答by AlfaZulu

Polling a.k.a busy waiting is not a good idea. As you mentioned, busy waiting wastes CPU cycles and can cause your application to appear unresponsive.

轮询又名忙等待不是一个好主意。正如您所提到的,忙等待会浪费 CPU 周期,并可能导致您的应用程序无响应。

My Java is rough, but you want something like the following:

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

If one thread has to wait for the output of another thread you should make use of a condition variable.

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

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

The thread interested in the output of the other threat should call cv.wait(). This will cause the current thread to block. When the worker thread is finished working, it should call cv.signal(). This will cause the blocked thread to become unblocked, allowing it to inspect the output of the worker thread.

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

回答by Nick Holt

As an alternative to the concurrency API as described by Saua (and if the main thread doesn't need to know when a worker thread finishes) you could use the publish/subscribe pattern.

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

In this scenario the child Thread/Runnableis given a listenerthat knows how to process the result and which is called back to when child Thread/Runnablecompletes.

在这种情况下,子Thread/Runnable被赋予一个侦听器,该侦听器知道如何处理结果并在子Thread/Runnable完成时回调。

回答by erickson

Your scenario is still a little unclear.

你的场景还是有点不清楚。

If you are running a batch job, you may want to use invokeAll. This will block your main thread until all the tasks are complete. There is no "busy waiting" with this approach, where the main thread would waste CPU polling the isDonemethod of a Future. While this method returns a list of Futures, they are already "done". (There's also an overloaded version that can timeout before completion, which might be safer to use with some tasks.) This can be a lot cleaner than trying to gather up a bunch of Futureobjects yourself and trying to check their status or block on their getmethods individually.

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

If this is an interactive application, with tasks sporadically spun off to be executed in the background, using a callbackas suggested by nick.holtis a great approach. Here, you use the submita Runnable. The runmethod invokes the callback with the result when it's been computed. With this approach, you may discard the Futurereturned by submit, unless you want to be able to cancelrunning tasks without shutting down the whole ExecutorService.

如果这是一个交互式应用程序,任务偶尔会在后台执行,使用nick.holt建议的回调是一个很好的方法。在这里,您使用a 。该方法在计算结果时调用带有结果的回调。使用这种方法,您可以丢弃返回的,除非您希望能够在不关闭整个.submitRunnablerunFuturesubmitcancelExecutorService

If you want to be able to cancel tasks or use the timeout capabilities, an important thing to remember is that tasks are canceled by calling interrupton their thread. So, your task needs to check its interrupted statusperiodically and abort as needed.

如果您希望能够取消任务或使用超时功能,要记住的一件重要事情是通过调用interrupt它们的线程来取消任务。因此,您的任务需要定期检查其中断状态并根据需要中止。

回答by skiphoppy

Subclass Thread, and give your class a method that returns the result. When the method is called, if the result hasn't been created, yet, then join() with the Thread. When join() returns, your Thread's work will be done and the result should be available; return it.

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

Use this only if you actually need to fire off an asynchronous activity, do some work while you're waiting, and then obtain the result. Otherwise, what's the point of a Thread? You might as well just write a class that does the work and returns the result in the main thread.

仅当您确实需要触发异步活动,在等待时做一些工作,然后获得结果时才使用它。否则,线程的意义何在?您不妨编写一个类来完成工作并在主线程中返回结果。

Another approach would be a callback: have your constructor take an argument that implements an interface with a callback method that will be called when the result is computed. This will make the work completely asynchronous. But if you at all need to wait for the result at some point, I think you're still going to need to call join() from the main thread.

另一种方法是回调:让您的构造函数接受一个参数,该参数实现一个带有回调方法的接口,该方法将在计算结果时调用。这将使工作完全异步。但是如果你在某个时候需要等待结果,我认为你仍然需要从主线程调用 join() 。

回答by Jeroen van Bergen

As noted by saua: use the constructs offered by java.util.concurrent. If you're stuck with a pre 1.5 (or 5.0) JRE, you ,might resort to kind of rolling your own, but you're still better of by using a backport: http://backport-jsr166.sourceforge.net/

正如 saua 所指出的:使用 java.util.concurrent 提供的构造。如果您坚持使用 1.5(或 5.0)之前的 JRE,您可能会诉诸于自己的滚动,但您仍然最好使用 backport:http: //backport-jsr166.sourceforge.net/