JavaFX自定义控制台中的线程冲突

时间:2013-08-22 17:58:50

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

我已经创建了一个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();


}

启动应用程序时,控制台会给我上面描述的异常,但是everthing工作正常。但是,如果应用程序生成异常,则控制台不会显示该异常并且所有内容都已锁定。我做错了什么?

1 个答案:

答案 0 :(得分:9)

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结构中。