簡體   English   中英

使用JavaFX的多線程導致java.lang.IllegalStateException:不在FX應用程序線程上

[英]Multithreading with JavaFX causes java.lang.IllegalStateException: Not on FX application thread

因此,我得到了一個相當簡單的JavaFX應用程序,該應用程序在按下開始按鈕時會創建並啟動2個線程。 我還有一個重置按鈕,該按鈕應該中斷線程並清除GUI組件。 這似乎很好。 然后,我應該能夠按下重置按鈕,然后再次按下啟動按鈕來創建2個線程,然后再次啟動它們。 這也有效。 當這些線程執行時,它們正在使用我的回調,將字符串還給我的Controller類,然后將其添加到列表視圖中。 第一次運行應用程序時,此方法運行良好,但是如果我按清除然后啟動,則在將數據添加到列表視圖時,回調會引發錯誤。 java.lang.IllegalStateException: Not on FX application thread

據我了解,每當main以外的其他線程嘗試更改fx元素時,都會引發此錯誤。 但是,為什么我第一次單擊“開始”而不是單擊“清除”然后重新開始后,它仍能正常工作? 這是我的代碼:

/**
 * Controls GUI and start threads..
 * 
 *
 */
public class Controller implements Initializable {
    @FXML
    private Button btnRun;

    @FXML
    private Button btnReset;

    @FXML
    private TextArea taInput;

    @FXML
    private ListView<String> lwProducer;

    @FXML
    private ListView<String> lwConsumer;

    private boolean sync;
    private Buffer buffer;
    private ObservableList<String> conData;
    private ObservableList<String> proData;
    private Thread consumerThread;
    private Thread producerThread;
    private Runnable producerR;
    private Runnable consumerR;

    /**
     * Initializes elements, sets an initial value for the textbox.
     */
    public void initialize(URL location, ResourceBundle resources) {
        taInput.setText("The quick brown\nfox jumps over\nthe lazy dog");
        btnReset.setDisable(true);
        btnRun.setDefaultButton(true);
        lwProducer.setStyle("-fx-focus-color: transparent;");
        lwConsumer.setStyle("-fx-focus-color: transparent;");
    }

    /**
     * Eventhandler for btnRun that will start new threads.
     * 
     * @param e
     */
    @FXML
    protected void btnRun(ActionEvent e) {
        System.out.println(sync);
        conData = FXCollections.observableArrayList();
        proData = FXCollections.observableArrayList();

        buffer = new Buffer();

        producerR = new Producer(new ProducerCB(), buffer, taInput.getText());
        consumerR = new Consumer(new ConsumerCB(), buffer);

        producerThread = new Thread(producerR);
        consumerThread = new Thread(consumerR);

        producerThread.start();
        consumerThread.start();

        btnRun.setDisable(true);
        taInput.setDisable(true);
        btnReset.setDisable(false);
    }

    /**
     * Eventhandler for btnReset. If pressed, threads and all gui components
     * will be cleared.
     * 
     * @param e
     */
    @FXML
    protected void btnReset(ActionEvent e) {
        System.out.println("Resetting");
        producerThread.interrupt();
        consumerThread.interrupt();
        producerThread = null;
        consumerThread = null;
        lwProducer.getItems().clear();
        lwConsumer.getItems().clear();
        conData = null
        proData = null
        producerR = null;
        consumerR = null;
        btnRun.setDisable(false);
        taInput.setDisable(false);
        btnReset.setDisable(true);
    }

    /**
     * Callback for producer thread. Updates the left hand listview with added
     * data.
     * 
     *
     */
    private class ProducerCB implements Callback {
        @Override
        public void returnData(String str) {
            proData.add(str);
            lwProducer.setItems(proData);
        }
    }

    /**
     * Callback for consumer thread. Updates the right hand listview with read
     * data.
     * 
     */
    private class ConsumerCB implements Callback {
        @Override
        public void returnData(String str) {
            conData.add(str); // Throws exception!!!!!!!
            lwConsumer.setItems(conData);
        }
    }
}

堆棧跟蹤

Exception in thread "Thread-7" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-7
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
    at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
    at com.sun.javafx.scene.control.skin.ListCellSkin.handleControlPropertyChanged(ListCellSkin.java:49)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
    at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
    at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
    at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
    at javafx.scene.control.Labeled.setText(Labeled.java:145)
    at com.sun.javafx.scene.control.skin.ListViewSkin$2.updateItem(ListViewSkin.java:319)
    at javafx.scene.control.ListCell.updateItem(ListCell.java:471)
    at javafx.scene.control.ListCell.lambda$new$160(ListCell.java:167)
    at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
    at java.util.AbstractList.add(AbstractList.java:108)
    at assignment2.Controller.addData(Controller.java:163)
    at assignment2.Controller.access$2(Controller.java:162)
    at assignment2.Controller$ConsumerCB.returnData(Controller.java:158)
    at assignment2.Consumer.run(Consumer.java:22)
    at java.lang.Thread.run(Thread.java:745)

與AWT事件調度程序線程類似,僅在使用該Java FX應用程序線程時才可以更新JavaFx UI組件。

有關此主題的更多信息 ,請參見此處 解決此類問題的一種方法是使用Platform.runLater()

根據Stacktrace,您正在非fx線程中更改某些fx元素的值(稱為“ Thread-7”,顯然這是您創建的匿名線程)。我認為您可以在conData.add(str)和查看呼叫層次結構,您將找到自己的根本原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM