简体   繁体   English

线程间的非阻塞信号

[英]Non-blocking signaling between threads

I have a JavaFX app that runs two threads at startup.我有一个 JavaFX 应用程序,它在启动时运行两个线程。 One is the UI thread that must not be blocked.一种是不得阻塞的 UI 线程。 The other is a thread that prepares a large table (it takes about 20 seconds).另一个是准备大表的线程(大约需要20秒)。 I want to signal the UI thread when the second thread is done, so it can change the color of a rectangle from red to green.我想在第二个线程完成时向 UI 线程发出信号,以便它可以将矩形的颜色从红色更改为绿色。 I have tried solutions using the synchronized keyword, but they all caused the UI thread to be blocked.我尝试过使用 synchronized 关键字的解决方案,但它们都导致 UI 线程被阻塞。

I used the following resources to obtain the below code.我使用以下资源获取以下代码。

The below app simply displays a red rectangle which, after five seconds, turns to green.下面的应用程序仅显示一个红色矩形,五秒钟后变为绿色。 Explanations after the code.代码后的解释。

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class JfxTask0 extends Application {
    private Task<Void>  task;

    @Override
    public void init() throws Exception {
        task = new Task<Void>() {
            
            @Override
            protected Void call() throws Exception {
                try {
                    Thread.sleep(5000L);
                }
                catch (InterruptedException xInterrupted) {
                    if (isCancelled()) {
                        System.out.println("CANCELLED!");
                    }
                }
                return null;
            }
        };
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Rectangle rect = new Rectangle(25.0d, 25.0d, 50.0d, 50.0d);
        rect.setFill(Color.RED);
        task.stateProperty().addListener(new ChangeListener<Worker.State>() {

            @Override
            public void changed(ObservableValue<? extends State> workerStateProperty,
                                Worker.State oldValue,
                                Worker.State newValue) {
                if (newValue == Worker.State.SUCCEEDED) {
                    rect.setFill(Color.GREEN);
                }
            }
        });
        new Thread(task).start();
        Group root = new Group();
        ObservableList<Node> children = root.getChildren();
        children.add(rect);
        Scene scene = new Scene(root, 100.0D, 100.0D);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Task");
        primaryStage.show();
    }

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

Method init() is declared in class javafx.application.Application .方法init()在 class javafx.application.Application中声明。 It is executed before method start() and, as its name suggests, is used to initialize the JavaFX application.它在方法start()之前执行,顾名思义,它用于初始化 JavaFX 应用程序。 In this method I create the background task.在这种方法中,我创建了后台任务。 The background task merely sleeps for five seconds.后台任务只休眠五秒钟。

In method start() I create the red rectangle and then launch the background task but before launching the task, I register a listener with one of the task's properties.在方法start()中,我创建了红色矩形,然后启动了后台任务,但在启动任务之前,我用任务的一个属性注册了一个侦听器。 This property will be set to a particular value once the task completes.任务完成后,此属性将设置为特定值。

After the task is launched, I build the rest of the GUI and display it.任务启动后,我构建了GUI的rest并显示出来。

Once the task terminates, then listener is invoked and it sets the rectangle color to green.任务终止后,将调用侦听器并将矩形颜色设置为绿色。

You can use a handler for this problem.您可以使用处理程序来解决此问题。 there is example Add this in your main activity and create handler.有示例将其添加到您的主要活动中并创建处理程序。

Handler h = new Handler(){
@Override public void handleMessage(Message msg){
switch(msg.what){
case 1:
    // what you want when complete 
    break;
default:
break;
}
}

}

MyThread thread = new MyThread(new Messenger(h));
thread.start();

Now add this in your thread file.现在将其添加到您的线程文件中。

public class MyThread{
Messenger m;
public MyThread(Messenger m){
this.m = m;
}

public void run(){
super.run();

// your codes

//
//when your task complete 
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "";
try{
m.send(msg);
}catch(IOException e){
e.printStackTrace();
}
}

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM