Concurrency 持续更新文本区域

Concurrency 持续更新文本区域,concurrency,javafx,textarea,task,Concurrency,Javafx,Textarea,Task,我正在编写一个程序,使用youtube dl创建一个进程。该进程有两个InputStreams(InputStream和errorStream),我想将其中的每一个重新路由到一个文本区域 我一直试图在不锁定JavaFX线程的情况下更新TextAreas。它正在工作,但我觉得它非常低效,因为它创建了大量只附加一行的任务对象。我重新创建了我在下面使用的代码,使用List而不是BufferedReader来简化问题 当我按下按钮时,它将创建两个线程,每个列表一个,带有UpdateTask。然后,Upd

我正在编写一个程序,使用youtube dl创建一个进程。该进程有两个
InputStream
s(InputStream和errorStream),我想将其中的每一个重新路由到一个文本区域

我一直试图在不锁定JavaFX线程的情况下更新
TextArea
s。它正在工作,但我觉得它非常低效,因为它创建了大量只附加一行的任务对象。我重新创建了我在下面使用的代码,使用
List
而不是
BufferedReader
来简化问题

当我按下按钮时,它将创建两个线程,每个列表一个,带有
UpdateTask
。然后,UpdateTask创建一个
WriteTask
并将其交给
Platform.runLater()
,然后将其再次放在JavaFX线程上

肯定有更好的办法吗

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class ConcurrentTest extends VBox{

    TextArea output;
    TextArea error;
    Button start;
    TextField writable;

    public ConcurrentTest(){
        // Init components
        output = new TextArea();
        output.setEditable(false);
        error = new TextArea();
        error.setEditable(false);
        // Init button
        start = new Button("Print stuff");
        start.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                List<String> outputLines = Arrays.asList("A", "B", "C", "D");
                List<String> errorLines = Arrays.asList("A", "B", "C", "D");;

                Thread outputThread = new Thread(new UpdateTask<String>(output, outputLines));
                outputThread.setDaemon(true);
                outputThread.start();

                Thread errorThread = new Thread(new UpdateTask<String>(error, errorLines));
                errorThread.setDaemon(true);
                errorThread.start();
            }
        });
        writable = new TextField();
        writable.setPromptText("Write while some text areas are getting updated.");

        // Add components
        this.getChildren().addAll(output, error, start, writable);
    }

    // UPDATE TASK CLASS
    public class UpdateTask<V> extends Task<V>{

        TextArea target;
        Iterator<String> it;

        public UpdateTask(TextArea target, List<String> lines){
            this.target = target;
            it = lines.iterator();
        }

        @Override
        protected V call() throws Exception {
            while(it.hasNext()){
                Thread.sleep(1500);     // Time to type something to test
                Platform.runLater(new WriteTask<String>(target, it.next()));
            }
            return null;
        }

    }

    // WRITE TASK CLASS
    public class WriteTask<V> extends Task<V>{

        TextArea target;
        String line;

        public WriteTask(TextArea target, String line) {
            this.target = target;
            this.line = line;
        }

        @Override
        protected V call() throws Exception {
            target.appendText(line + "\n");
            return null;
        }
    }
}

这里的解决方案应该是100%相同的:
Task
s相对较轻;您只想避免创建许多
线程。您只需在每次单击按钮时创建一个新线程,这应该很好。如果你看到性能问题,你可以考虑创建一个单一的,并提交<代码> UpDestTebug < /代码> s;但是我不认为这里会有问题。@James_D我以为用大量的
任务调用
Platform.runLater()
效率会很低,我会继续使用这个系统。谢谢你的评论!每1.5秒节流一次,这样就可以了。如果您反复调用
Platform.runLater(…)
,而不阻塞,您将淹没FX应用程序线程并使UI无响应,但(据我所知)您在这里没有这样做。@James\D每秒调用15次会不会太多?因此,在我的示例中,我有两个线程,每个线程进行15次
runLater()
调用,每秒总共进行30次调用。我如何检查性能?我不太熟悉多线程。
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class ConcurrentTestLauncher extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = new ConcurrentTest();
            Scene scene = new Scene(root);
            primaryStage.setTitle("Concurrent FX Test");
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}