【问题标题】:Threads collision in JavaFX Custom ConsoleJavaFX 自定义控制台中的线程冲突
【发布时间】:2013-08-22 17:58:49
【问题描述】:

我已经制作了一个 Java/JavaFX 控制台,但现在我遇到了一个异常:Console reports an Internal error.The error is: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5。控制台代码:

package core.console;
import javafx.concurrent.Service;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;

import java.io.*;
import java.util.ResourceBundle;

public class Console implements Runnable{
    private Console(ResourceBundle resourceBundle) throws IOException {
        FXMLLoader loader = new FXMLLoader(this.getClass().getResource("Console.fxml"), resourceBundle);
        Parent root = (Parent) loader.load();
        controller = loader.getController();
        Scene scene = new Scene(root);
        stage = new Stage();
        stage.setScene(scene);
        textArea = controller.getTextArea();
        show();

        PipedOutputStream pout=new PipedOutputStream(this.pin);
        System.setOut(new PrintStream(pout,true));

        PipedOutputStream pout2=new PipedOutputStream(this.pin2);
        System.setErr(new PrintStream(pout2,true));

        System.setIn(new PipedInputStream(this.pout3));

        reader = new Thread(this);
        reader.setDaemon(true);
        reader.start();

        reader2 = new Thread(this);
        reader2.setDaemon(true);
        reader2.start();
    }   

    public static Console getInstance(ResourceBundle resourceBundle) {
        if (console == null) {
            try {
                console = new Console(resourceBundle);
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        return console;
    }

    public void show() {
        stage.show();
    }

    @Override
    public synchronized void run()
    {
        try
        {
            while (Thread.currentThread()==reader)
            {
                try {
                    this.wait(100);
                } catch(InterruptedException ie) {}
                if (pin.available()!= 0)
                {
                    String input=this.readLine(pin);
                    controller.appendText(input);
                }
                if (quit) return;
            }

            while (Thread.currentThread()==reader2)
            {
                try {
                    this.wait(100);
                } catch(InterruptedException ie) {}
                if (pin2.available()!= 0)
                {
                    String input = this.readLine(pin2);
                    controller.appendText(input);
                }
                if (quit) return;
            }
        } catch (Exception e)
        {
            controller.appendText("\nConsole reports an Internal error.");
            controller.appendText("The error is: "+e);
        }

    }

    private synchronized String readLine(PipedInputStream in) throws IOException
    {
        String input="";
        do
        {
            int available=in.available();
            if (available==0) break;
            byte b[]=new byte[available];
            in.read(b);
            input=input+new String(b,0,b.length);
        }while( !input.endsWith("\n") &&  !input.endsWith("\r\n") && !quit);
        return input;
    }   

    private static Console console = null;
    private ConsoleController controller;
    private Stage stage;
    private TextArea textArea;
    private Thread reader;
    private Thread reader2;

    private final PipedInputStream pin=new PipedInputStream();
    private final PipedInputStream pin2=new PipedInputStream();
    private final PipedOutputStream pout3=new PipedOutputStream();


}

启动应用程序时,控制台给了我上述异常,但一切正常。但是如果应用程序产生了异常,控制台不会显示它并且一切都被锁定了。我做错了什么?

【问题讨论】:

    标签: java multithreading javafx-2 jconsole javafx-8


    【解决方案1】:

    JavaFX 是一个单线程工具包。您永远不应该从后台线程查询或更新 UI。因此,您需要使用

    包装对 JFX 类的所有调用
    Platform.runLater(new Runnable() {
       @Override
       public void run() {
          // Update/Query the FX classes here
       }
    });
    

    在您的上下文中,Console.run() 方法中的代码在 JavaFX 应用程序线程之外执行,因此它不应该通过调用 controller.appendText() 直接修改 UI 对象。在您的情况下,所有controller.appendText() 调用都应包含在上面定义的Platform.runLater 构造中。

    【讨论】:

    • 抱歉,我不明白如何在我的上下文中使用此代码。
    • @Eugene 我编辑了答案以解释如何在您的上下文中使用Platform.runLater
    • @jewelsea 非常感谢
    • @jewelsea 我已经尝试过了,但是打印异常需要很长时间(~ 5-10 秒)。有没有其他方法可以做到这一点?
    猜你喜欢
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 2012-05-18
    相关资源
    最近更新 更多