java - 如何在 JavaFX 中对任务进行排队?

标签 java multithreading javafx

我使用 JavaFX 制作了一个 GUI,它有三个单选按钮,一旦用户单击提交并创建另一个线程,根据选中的单选按钮,该线程运行所需的输出并将结果输出到控制台。

但是当线程运行时(完成一个进程大约需要 30 秒),我可以检查任何单选按钮。它创建另一个线程并与另一个正在进行的线程一起输出 long 。所以我的输出框只是一个困惑!我正在查看异步任务,但我不确定这是否与它相关。

这是我需要的:如果一个任务正在运行,我在它运行时点击了提交按钮,等待上一个任务结束,然后执行任务。

这是我的伪代码

class TestMain {

    //main

    public void main(String ... args)  {

        launch(args);
    }

    /*declaring a new textfield with name m_status update here*/
    

    /*once submit button is clicked*/{

        //create a new thread 
        //to run   
    }
}

class ThreadBlahBlah implements Runnable {

    if(/*first checkbox was selected*/){
        //do these fancy stuff
        Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    TestMain.m_status_update.setText("Test Completed!");
                }
        });
    
    }else if(/*second checkbox was selected*/){
        //do these other fancy stuff
        Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    TestMain.m_status_update.setText("Test Completed!");

                }
            });
    }
}

请不要建议我在任务运行时禁用单选按钮,因为我想像链表一样对任务进行排队。

最佳答案

使用单线程执行器来运行您的任务:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class QueuedTaskExample extends Application {

    private AtomicInteger taskCount = new AtomicInteger(0);

    private ExecutorService exec = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r);
        t.setDaemon(true); // allows app to exit if tasks are running
        return t ;
    });

    // Use the following if you want the tasks to run concurrently, instead of consecutively:

    // private ExecutorService exec = Executors.newCachedThreadPool(r -> {
    //     Thread t = new Thread(r);
    //     t.setDaemon(true);
    //     return t ;
    // });


    @Override
    public void start(Stage primaryStage) {

        // Just keep track of number of tasks pending/running for a status label:
        IntegerProperty pendingTasks = new SimpleIntegerProperty(0);

        Button startButton = new Button("Start");
        TextArea textArea = new TextArea();
        textArea.setEditable(true);
        startButton.setOnAction(event -> {
            Task<Void> task = createTask();
            // add text to text area if task's message changes:
            task.messageProperty().addListener((obs, oldMessage, newMessage) -> {
                textArea.appendText(newMessage);
                textArea.appendText("\n");
            });

            // for maintaining status label:
            pendingTasks.set(pendingTasks.get()+1);
            task.setOnSucceeded(taskEvent -> pendingTasks.set(pendingTasks.get()-1));

            // run task in single-thread executor (will queue if another task is running):
            exec.submit(task);
        });

        // layout etc
        HBox controls = new HBox(startButton);
        controls.setAlignment(Pos.CENTER);
        controls.setPadding(new Insets(10));

        Label statusLabel = new Label();
        statusLabel.textProperty().bind(Bindings.format("Pending/running tasks: %s", pendingTasks));

        BorderPane root = new BorderPane(textArea, statusLabel, null, controls, null);
        Scene scene = new Scene(root, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    @Override
    public void stop() {
        exec.shutdownNow();
    }

    // Trivial task that counts slowly to 5, updating its message as it goes:
    private Task<Void> createTask() {
        final int taskNumber = taskCount.incrementAndGet();
        return new Task<Void>() {
            @Override 
            public Void call() throws Exception {
                for (int count=1; count<=5; count++) {
                    Thread.sleep(1000);
                    updateMessage("Task "+taskNumber+": Count "+count);
                }
                return null ;
            }
        };
    }

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

关于java - 如何在 JavaFX 中对任务进行排队?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26611042/

相关文章:

java - 如何处理PreparedStatement中的单引号?

java - 如何分别在特定行中插入列值?

android - RxJava : return a cached value synchronously/immediately

JavaFX: 'disabling' TableView 行和列

Java任务什么都不做?

java - 结合 Google Maps API 和 Google Maps Data API

java - libGDX - 使用 HashMap 会导致 Android 手机上的 HeapSize 增加和内存不足

java - Java获取线程ID的方法

C++ 多线程 : explicit locks in domain model classes

java - 将 ListView 绑定(bind)到 ObservableSet