变量内部线程在某些时候为空

时间:2015-11-27 08:46:17

标签: java multithreading

我在ArrayList内的ThreadonStart方法中访问了JavaFX。当我尝试再次使用由ArrayList触发的方法从另一个Thread访问MenuItem时,我无法理解原因。< / p>

示例程序:

package sample;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.util.ArrayList;

public class Main extends Application {

    private ArrayList<Integer> testArray;
    private Thread t;

    @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
        fxmlLoader.setController(new Main());
        Parent root = (Parent)fxmlLoader.load();
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();

        testArray = new ArrayList<>();
        testArray.add(10);
        t = new Thread(() -> {
            System.out.println("Test number is "+testArray.get(0));
        });

        t.start();
    }

    @FXML
    public void menuItemActionMethod(ActionEvent event) {
        Thread t2t = new Thread(() -> {
            System.out.println("Test number is "+testArray.get(0));
        });

        t2t.start();
    }


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

sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>


<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
   <children>
      <Pane prefHeight="200.0" prefWidth="200.0">
         <children>
            <MenuBar>
              <menus>
                <Menu mnemonicParsing="false" text="File">
                  <items>
                    <MenuItem mnemonicParsing="false" text="Close" />
                  </items>
                </Menu>
                <Menu mnemonicParsing="false" text="Edit">
                  <items>
                    <MenuItem mnemonicParsing="false" onAction="#menuItemActionMethod" text="Delete" />
                  </items>
                </Menu>
                <Menu mnemonicParsing="false" text="Help">
                  <items>
                    <MenuItem mnemonicParsing="false" text="About" />
                  </items>
                </Menu>
              </menus>
            </MenuBar>
         </children>
      </Pane>
   </children>
</GridPane>

输出如下:

Test number is 10
Exception in thread "Thread-5" java.lang.NullPointerException
    at sample.Main.lambda$menuItemActionMethod$1(Main.java:39)
    at java.lang.Thread.run(Thread.java:745)

我在menuItemActionMethod Delete的FXML中附加了MenuItem。运行示例并在应用程序中访问Delete应运行Method

1 个答案:

答案 0 :(得分:1)

现在我们终于得到了一个repro,问题只是在menuItemActionMethod方法的Main的另一个实例上调用了start

不是JavaFX开发人员,我不能轻易地遵循此处的代码流程,但您可以通过完全删除线程来简单地演示这一点:

private String name = "none set";

@Override
public void start(Stage primaryStage) throws Exception{
    name = "set in start";
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
    fxmlLoader.setController(new Main());
    Parent root = (Parent)fxmlLoader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();
}

@FXML
public void menuItemActionMethod(ActionEvent event) {
    System.out.println("In menuItemActionMethod: " + name);
}

当您点击菜单项时,您会看到:

In menuItemActionMethod: none set

表示对menuItemActionMethod的呼叫是在与start被呼叫的对象不同的对象上进行的。

后续步骤:

  • 阅读有关JavaFX对象生存期的更多信息
  • 找出如何找到 将在事件处理程序中使用的Main实例
  • 理想情况下,将初始化类与事件处理类分开,以便更难以进入这种情况开始