在SwingWorker

时间:2017-11-27 23:17:30

标签: java multithreading swing user-interface nullpointerexception

我正在制作这个JavaFX质量计算器,它基本上由一个按钮执行SwingWorker后台线程来计算某些比率或因子或其他因素。

我已经意识到,对于我的因子和素因子计算(当我试图找到用户输入的数字的所有因子和素因子时),我在计算完成后得到NullPointerException表演大约3-5次。

这是单击按钮时执行的脚本:

public static longCalculationThread calculationThread;

//Called by the calculate button
@FXML
void callCalculation(ActionEvent event) throws IOException, InterruptedException {

    Long number = 0L;
    Long lowerBound = 0L;
    Long higherBound = 0L;

    try {
        //Bunch of input verification logic here. The logic here also creates the variables for the thread bundle

        //Enabling progress UI since no errors were encoundered...
        excelPane.setVisible(false); 
        progressPane.setDisable(false);
        progressPane.setVisible(true);

        //Preparing threadBundle, which is just a bunch of fields out into a data holding class [not shown]

        calculationThread = new longCalculationThread(threadBundle);
        calculationThread.execute();
        System.gc(); //For the objects of the previous calculationThread
    }
}  

以下是longCalculationThread的结构:

package PrimusForPC;

public class longCalculationThread extends SwingWorker<Void, Void> {

private ArrayList<Long> longResults = new ArrayList<>();
private ArrayList<String> stringResults = new ArrayList<>();

private calculationHolder.calculationType type;
private JFXProgressBar progressBar;
private Text progressText;
private GridView<String> answerGridView;
private Pane mainPane, progressPane;
private long mainNumber, lowerNum, upperNum;
private boolean shouldExport;
private ExcelWriter.spreadsheetTypes exportType;
private int excelExportLimit;
private JFXButton calcButton;
private Menu selectionMenu;

private static double acceptableAccuracy = 0.004; //The degree of accuracty for pi and phi couples
public static final double PHI = 1.6180339887498948482045;

public boolean shouldDie; //Called externally to kill the thread. Hasn't been implemented yet


longCalculationThread(threadArgumentBundle bundle){
    progressBar = bundle.progressBar;
    answerGridView = bundle.answerGridView;
    type = bundle.type;
    mainNumber = bundle.primaryNumber;
    upperNum = bundle.upperNum;
    lowerNum = bundle.lowerNum;
    progressText = bundle.progressText;
    mainPane = bundle.mainPane;
    progressPane = bundle.progressPane;
    exportType = bundle.exportType;
    shouldExport = bundle.shouldExport;
    excelExportLimit = bundle.excelExportLimit;   
    calcButton = bundle.button;
    selectionMenu = bundle.selectionMenu;   
}


@Override
public Void doInBackground(){
    System.out.println("Thread started " + Thread.currentThread().getName());
    Platform.runLater(new Runnable() {
    @Override
    public void run() {
        progressBar.isIndeterminate();
        progressBar.progressProperty().setValue(0);
        calcButton.setDisable(true);
        selectionMenu.setDisable(true);
      }
    });

    switch (type){
        case factors:
            findfactors();
            break;
        case primeFactors:
            findPrimeFactors();
            break;
        case primesUpToX:
            findPrimesUpToX();
            break;
//Bunch of other cases here...       
    }
    try {
        publishResults();
    } catch (IOException | InterruptedException ex) {
        Logger.getLogger(longCalculationThread.class.getName()).log(Level.SEVERE, null, ex);
    }
    reEndableInterface();
    System.gc();
    System.out.println("Thread ended " + Thread.currentThread().getName() + "\n");
    return null;
}


static private long getSquareRoot (long number){
    //For calculations square root only matters for larger numbers
    //for numbers below 5 it doesn't really matter
    if (number > 5){
        number =  (long) Math.ceil(Math.sqrt(number));
    }
return number;
}


private void findfactors(){
    progressText.setText("Finding factors...");
    long root = getSquareRoot(mainNumber);
    double incrementValue = 1/(double)root;
      for (long divisor = 1; divisor <= root; divisor++) {
       setProgressBar(progressBar.getProgress() + incrementValue);
       if (mainNumber % divisor == 0) {
           longResults.add(divisor);
           longResults.add((mainNumber/divisor));
       }
   }
}


private void findPrimeFactors(){
    findfactors();
    progressText.setText("Separating prime factors from composite factors...");
    progressBar.progressProperty().set(0);
    double incrementValue = 1/(double)longResults.size();
    ArrayList <Long> realResults = new ArrayList<>();
    for (long factor: longResults){
       if (isPrime(factor)) realResults.add(factor);
       setProgressBar(progressBar.getProgress() + incrementValue);
    }

    longResults = realResults;
}


static boolean isPrime(long number){
    if (number == 1) return false;
    if (number == 2 || number == 3 || number == 5) return true;
    long root = getSquareRoot(number);
    for (int divisor = 2; divisor <= root; divisor++)
        if (number % divisor == 0) return false;
    return true;
}


private void publishResults() throws IOException, InterruptedException{

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                answerGridView.getItems().setAll(stringResults);
              }
            });          

//To make UI interface useable again
private void reEndableInterface(){
     Platform.runLater(new Runnable() {
            @Override
            public void run() {
                progressPane.setDisable(true);
                progressPane.setVisible(false);
                mainPane.setDisable(false);
                mainPane.setVisible(true);
                calcButton.setDisable(false);
                System.out.println("Button enabled " + Thread.currentThread().getName());
                selectionMenu.setDisable(false);
              }
            });
}

我不确定NullPointerException来自哪里,或者为什么它似乎只是在我使用&#34;发现因素&#34;或者&#34;找到素数因素&#34;计算。这是一个错误日志(对不起,这么久,不知道在哪里切断)。

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.text.PrismTextLayout.addTextRun(PrismTextLayout.java:755)
at com.sun.javafx.text.GlyphLayout.addTextRun(GlyphLayout.java:140)
at com.sun.javafx.text.GlyphLayout.breakRuns(GlyphLayout.java:312)
at com.sun.javafx.text.PrismTextLayout.buildRuns(PrismTextLayout.java:770)
at com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1021)
at com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:223)
at com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:246)
at javafx.scene.text.Text.getLogicalBounds(Text.java:358)
at javafx.scene.text.Text.impl_computeGeomBounds(Text.java:1168)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.impl_intersectsBounds(Node.java:5013)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2931)
at javafx.scene.Node.impl_pickNode(Node.java:4912)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2936)
at javafx.scene.Node.impl_pickNode(Node.java:4912)
at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3899)
at javafx.scene.Scene$MouseHandler.access$1600(Scene.java:3485)
at javafx.scene.Scene.pick(Scene.java:1942)
at javafx.scene.Scene.access$6700(Scene.java:159)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3799)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)

然后最后控制台只是垃圾邮件:

    java.lang.ArrayIndexOutOfBoundsException

无限期。

正如我所说,我真的不知道为什么会这样。计算最初几次,然后发生此错误并冻结应用程序,需要完全重启。

1 个答案:

答案 0 :(得分:0)

感谢评论我的问题的人 - 链接显示了问题!

我使用的是SwingWorker,因为我希望能够直接影响UI线程(因为如果反复且频繁地调用,Program.runLater可能会泛滥UI线程。)

事实证明,SwingWorkers在JavaFX中不具备该功能,所以我试图直接影响UI线程导致了这些错误。所以,我回到使用Thread,并使用了注释中链接提供的限制逻辑。这允许我在线程中使用Program.runLater而不会泛滥UI线程。