当前位置: 首页 > 面试题库 >

执行onclickBtn后多线程应用程序挂起

酆浩邈
2023-03-14
问题内容

我正在用javaFx编写天气应用程序,以从openweather.org获取数据。从openweather获取JSON的整个代码运行良好,也可以将JSON数据转换为对象。我用lambda表达式来实现RunnablePlatform.runLater();。问题是:如果我运行Main
class,请按按钮,该应用程序将挂起。导入数据的线程有效(在控制台上通过2次打印检查),主线程“跳过”
Platform.runLater();并在控制台上打印某些内容。我不确定这里出什么问题了。

我的控制器类:

package sample;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

import java.time.LocalTime;
import java.util.ArrayList;


    public class Controller implements Observable{


        private static final WeatherStation WEATHER_STATION = new WeatherStation();
        protected volatile boolean isRunning = false;
        private String response;

    private static final int _5MINUTES = 1000*60*5;
    private volatile ArrayList<Observer> observers = new ArrayList<>();


    @FXML
    private TextField cityTextfield;

    @FXML
    private CategoryAxis xAxis;

    @FXML
    private NumberAxis yAxis;

    @FXML
    private Button btn;

    @FXML
    private LineChart<String, Number> plot;

    @FXML
    void onclickBtn(ActionEvent event) throws InterruptedException {
        WeatherUpdater weatherUpdater = new WeatherUpdater(plot);
        setSettings();
        WeatherObserver wroclaw = new WeatherObserver();
        weatherUpdater.addObserver(wroclaw);

        Platform.runLater(()->{
            isRunning = true;
            while(isRunning) try {
                addObserver(wroclaw);
                PlotDataUpdater<String, Number> dataUpdater = new PlotDataUpdater<>();
                WEATHER_STATION.sendQuery();
                response = WEATHER_STATION.getCurrentResponse();
                updateObservers();
                WeatherConditions weatherConditions = observers.get(0).getWeatherConditions();

                LocalTime currentTime = LocalTime.of(LocalTime.now().getHour(), LocalTime.now().getMinute());

                dataUpdater.updateSeries(currentTime.toString(), weatherConditions.getMainTemp());

                dataUpdater.updatePlot(plot);
                Thread.currentThread().sleep(_5MINUTES);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("Thread interrupted");
            }
        });

        System.out.println(".................................");
    }


    @Override
    public void addObserver(Observer observer) {
        if(!observers.contains(observer)) observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        if(observers.contains(observer)) observers.remove(observer);
    }

    @Override
    public void updateObservers() {
        for(Observer o : observers){
            o.updateWeatherInfo(response);
        }
    }

    private void setSettings(){
        plot.getData().clear();
        xAxis.setAutoRanging(true);
        yAxis.setAutoRanging(true);
        plot.setAnimated(false);
    }

}

用于生成绘图数据,从JSON转换事物的类按预期工作。如果需要更多代码,请发表评论。

@Edit:用于实现类的代码ObservableRunnable用自己的线程:

package sample;

import javafx.scene.chart.XYChart;

import java.time.LocalTime;
import java.util.ArrayList;

public class WeatherUpdater implements Runnable, Observable{

    private Thread updater;
    private static final WeatherStation WEATHER_STATION = new WeatherStation();
    protected volatile boolean isRunning = false;
    private String response;
    private static final int _5MINUTES = 1000*60*5;
    private volatile ArrayList<Observer> observers = new ArrayList<>();
    private XYChart<String, Number> plot;

    public WeatherUpdater(XYChart<String, Number> plot) {
        this.plot = plot;
    }

    public WeatherUpdater() {

    }

    public void start(){
        updater = new Thread(this,"Weather updater");
        updater.start();
    }

    public void interrupt(){
        isRunning = false;
        updater.interrupt();
    }

    public XYChart<String, Number> getPlot() {
        return plot;
    }


    @Override
    public void run() {
        isRunning = true;
        while(isRunning){
            try{
                PlotDataUpdater<String, Number> dataUpdater = new PlotDataUpdater<>();
                WEATHER_STATION.sendQuery();
                response = WEATHER_STATION.getCurrentResponse();
                updateObservers();
                WeatherConditions weatherConditions = observers.get(0).getWeatherConditions();

                LocalTime currentTime = LocalTime.of(LocalTime.now().getHour(), LocalTime.now().getMinute());

                dataUpdater.updateSeries(currentTime.toString(), weatherConditions.getMainTemp());

                dataUpdater.updatePlot(plot);
                Thread.sleep(_5MINUTES);
            } catch (InterruptedException e) {
                updater.interrupt();
                System.out.println("Thread interrupted" );
            }
        }
    }

    @Override
    public void addObserver(Observer observer) {
        if(!observers.contains(observer)) observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        if(observers.contains(observer)) observers.remove(observer);
    }

    @Override
    public void updateObservers() {
        for(Observer o : observers){
            o.updateWeatherInfo(response);
        }
    }
}

结合上面的类对“ onclickBtn”方法的修改:

@FXML
    void onclickBtn(ActionEvent event) throws InterruptedException {
        WeatherUpdater weatherUpdater = new WeatherUpdater(plot);
        setSettings();
        WeatherObserver wroclaw = new WeatherObserver();
        weatherUpdater.addObserver(wroclaw);
        weatherUpdater.start();


        System.out.println(".................................");
    }

控制台输出:

.................................
Server status: 200
Exception in thread "Weather updater" java.lang.IllegalStateException: Not on FX application thread; currentThread = Weather updater
    at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:424)
    at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:471)
    at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
    at javafx.controls/javafx.scene.chart.LineChart.seriesAdded(LineChart.java:405)
    at javafx.controls/javafx.scene.chart.XYChart.lambda$new$1(XYChart.java:160)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.base/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.base/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.base/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.base/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at javafx.base/javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
    at javafx.base/javafx.collections.ObservableListBase.setAll(ObservableListBase.java:251)
    at sample.PlotDataUpdater.updatePlot(PlotDataUpdater.java:36)
    at sample.WeatherUpdater.run(WeatherUpdater.java:56)
    at java.base/java.lang.Thread.run(Thread.java:834)

问题答案:

我认为您误解了Plaftform.runLater的用途。它不是用于运行后台任务,实际上是完全相反的:它是用于将任务委派给JavaFX应用程序线程(或为简单起见而委托给JavaFX应用程序中的“主线程”)。

根据您的描述,我想您想做的是在后台线程中从Web API获取数据,以免阻塞应用程序。为此,您可以使用JavaFX
Task
,请注意,为了在以后更新GUI,您需要使用Plaftform.runLater



 类似资料:
  • 我搜索了关于测量Java应用程序执行时间的信息,得到了以下代码: 开始和停止之间的差异给了我执行时间。 注意:我知道这不是确切的执行时间。我只是需要多线程和单线程应用程序之间的比较的时间。 如果我这样更改代码会怎样: 执行10个线程。不管他们做什么。假设他们随机填充一个二维数组。 现在,stop-start给了我“全部”执行时间?或者我必须自己测量线程吗?

  • 我正在开发一个java应用程序,其中我使用java swing窗体和javafx FXML stage,我对javafx是新手,现在我在应用程序中调用具有控制器的javafx FXML stage,从swing窗体调用FXML stage,单击如下按钮----application.launch(myfxml.class); 下面的代码片段用于调用swing表单-- 我得到的异常是“应用程序启动必

  • 6.7.2.多线程执行 与在单线程中阻塞相比,更好的做法是让程序运行在多个线程之中。系统负责分配CPU时间,几个线程仿佛在同一时刻同时运行。这样可以避免某线程独占计算资源。 图6.10. 多线程执行 在例子中,我们将网络操作的相关代码放到独立的线程里面。这样我们的主线程可以避免阻塞在网络操作上,用户界面不会响应不灵。按惯例,我们一般认为主线程是运行于前台,而其它的线程都是运行于后台。这是因为前端的

  • 我正在尝试通过TestNG进行多线程测试为测试实例化WebDrivers<代码>@AfterMethod在测试后关闭WebDrivers

  • 我正在使用在线程上运行的 SurfaceView 类中的画布。SurfaceView 由 Activity (setContentView(surfaceview)) 调用。当屏幕关闭时,它会通过一个 pause() 方法关闭所有循环变量等。 奇怪的是:虽然在我的平板电脑(Android 4.4.2)线程暂停和恢复正确(线程重新开始),但是在我的手机(Android 4.2.2)和其他人的手机(C

  • 问题内容: 为了在Linux上开发高度网络密集型服务器应用程序,首选哪种架构?这个想法是,该应用通常可以在具有多个内核(虚拟或物理)的机器上运行。考虑到性能是关键标准,选择多线程应用程序还是采用多进程设计更好?我确实知道资源共享和从多个进程访问此类资源的同步是很多编程开销,但是如前所述,整体性能是关键要求,因此我们可以忽略这些事情。编程语言为C / C ++。 我听说,即使是多线程应用程序(单个进