线程之间的非阻塞信号传递

huangapple go评论92阅读模式
英文:

Non-blocking signaling between threads

问题

我有一个JavaFX应用,在启动时运行两个线程。一个是UI线程,不能被阻塞。另一个是准备一个大表格的线程(大约需要20秒)。我想在第二个线程完成时通知UI线程,这样它就可以将一个矩形的颜色从红色更改为绿色。我尝试过使用synchronized关键字的解决方案,但它们都导致了UI线程被阻塞。

英文:

I have a JavaFX app that runs two threads at startup. One is the UI thread that must not be blocked. The other is a thread that prepares a large table (it takes about 20 seconds). 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. I have tried solutions using the synchronized keyword, but they all caused the UI thread to be blocked.

答案1

得分: 1

我使用了以下资源来获取下面的代码。

下面的应用程序简单地显示一个红色矩形,经过五秒钟后会变成绿色。在代码之后进行解释。

  1. import javafx.application.Application;
  2. import javafx.beans.value.ChangeListener;
  3. import javafx.beans.value.ObservableValue;
  4. import javafx.collections.ObservableList;
  5. import javafx.concurrent.Task;
  6. import javafx.concurrent.Worker;
  7. import javafx.concurrent.Worker.State;
  8. import javafx.scene.Group;
  9. import javafx.scene.Node;
  10. import javafx.scene.Scene;
  11. import javafx.scene.paint.Color;
  12. import javafx.scene.shape.Rectangle;
  13. import javafx.stage.Stage;
  14. public class JfxTask0 extends Application {
  15. private Task<Void> task;
  16. @Override
  17. public void init() throws Exception {
  18. task = new Task<Void>() {
  19. @Override
  20. protected Void call() throws Exception {
  21. try {
  22. Thread.sleep(5000L);
  23. }
  24. catch (InterruptedException xInterrupted) {
  25. if (isCancelled()) {
  26. System.out.println("CANCELLED!");
  27. }
  28. }
  29. return null;
  30. }
  31. };
  32. }
  33. @Override
  34. public void start(Stage primaryStage) throws Exception {
  35. Rectangle rect = new Rectangle(25.0d, 25.0d, 50.0d, 50.0d);
  36. rect.setFill(Color.RED);
  37. task.stateProperty().addListener(new ChangeListener<Worker.State>() {
  38. @Override
  39. public void changed(ObservableValue<? extends State> workerStateProperty,
  40. Worker.State oldValue,
  41. Worker.State newValue) {
  42. if (newValue == Worker.State.SUCCEEDED) {
  43. rect.setFill(Color.GREEN);
  44. }
  45. }
  46. });
  47. new Thread(task).start();
  48. Group root = new Group();
  49. ObservableList<Node> children = root.getChildren();
  50. children.add(rect);
  51. Scene scene = new Scene(root, 100.0D, 100.0D);
  52. primaryStage.setScene(scene);
  53. primaryStage.setTitle("Task");
  54. primaryStage.show();
  55. }
  56. public static void main(String[] args) {
  57. launch(args);
  58. }
  59. }

方法init()在类javafx.application.Application中声明。它在方法start()之前执行,正如其名称所示,用于初始化JavaFX应用程序。在这个方法中,我创建了后台任务。后台任务只是简单地睡眠了五秒钟。

在方法start()中,我创建了红色矩形,然后启动了后台任务,但在启动任务之前,我为任务的一个属性注册了一个监听器。一旦任务完成,该属性将被设置为特定的值。

任务启动后,我构建了剩余的GUI并显示它。

一旦任务终止,监听器就会被调用,它将矩形的颜色设置为绿色。

英文:

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.

  1. import javafx.application.Application;
  2. import javafx.beans.value.ChangeListener;
  3. import javafx.beans.value.ObservableValue;
  4. import javafx.collections.ObservableList;
  5. import javafx.concurrent.Task;
  6. import javafx.concurrent.Worker;
  7. import javafx.concurrent.Worker.State;
  8. import javafx.scene.Group;
  9. import javafx.scene.Node;
  10. import javafx.scene.Scene;
  11. import javafx.scene.paint.Color;
  12. import javafx.scene.shape.Rectangle;
  13. import javafx.stage.Stage;
  14. public class JfxTask0 extends Application {
  15. private Task&lt;Void&gt; task;
  16. @Override
  17. public void init() throws Exception {
  18. task = new Task&lt;Void&gt;() {
  19. @Override
  20. protected Void call() throws Exception {
  21. try {
  22. Thread.sleep(5000L);
  23. }
  24. catch (InterruptedException xInterrupted) {
  25. if (isCancelled()) {
  26. System.out.println(&quot;CANCELLED!&quot;);
  27. }
  28. }
  29. return null;
  30. }
  31. };
  32. }
  33. @Override
  34. public void start(Stage primaryStage) throws Exception {
  35. Rectangle rect = new Rectangle(25.0d, 25.0d, 50.0d, 50.0d);
  36. rect.setFill(Color.RED);
  37. task.stateProperty().addListener(new ChangeListener&lt;Worker.State&gt;() {
  38. @Override
  39. public void changed(ObservableValue&lt;? extends State&gt; workerStateProperty,
  40. Worker.State oldValue,
  41. Worker.State newValue) {
  42. if (newValue == Worker.State.SUCCEEDED) {
  43. rect.setFill(Color.GREEN);
  44. }
  45. }
  46. });
  47. new Thread(task).start();
  48. Group root = new Group();
  49. ObservableList&lt;Node&gt; children = root.getChildren();
  50. children.add(rect);
  51. Scene scene = new Scene(root, 100.0D, 100.0D);
  52. primaryStage.setScene(scene);
  53. primaryStage.setTitle(&quot;Task&quot;);
  54. primaryStage.show();
  55. }
  56. public static void main(String[] args) {
  57. launch(args);
  58. }
  59. }

Method init() is declared in class javafx.application.Application. It is executed before method start() and, as its name suggests, is used to initialize the JavaFX application. 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. 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.

Once the task terminates, then listener is invoked and it sets the rectangle color to green.

答案2

得分: 0

你可以为这个问题使用一个处理程序。
这里有一个示例。
在你的主活动中添加以下内容并创建处理程序。

  1. Handler h = new Handler(){
  2. @Override
  3. public void handleMessage(Message msg){
  4. switch(msg.what){
  5. case 1:
  6. // 在完成时执行的操作
  7. break;
  8. default:
  9. break;
  10. }
  11. }
  12. };
  13. MyThread thread = new MyThread(new Messenger(h));
  14. thread.start();

现在在你的线程文件中添加以下内容。

  1. public class MyThread extends Thread {
  2. Messenger m;
  3. public MyThread(Messenger m){
  4. this.m = m;
  5. }
  6. @Override
  7. public void run(){
  8. super.run();
  9. // 你的代码
  10. // 当任务完成时
  11. Message msg = Message.obtain();
  12. msg.what = 1;
  13. msg.obj = "";
  14. try{
  15. m.send(msg);
  16. } catch(IOException e){
  17. e.printStackTrace();
  18. }
  19. }
  20. }
英文:

You can use a handler for this problem.
there is example
Add this in your main activity and create handler.

  1. Handler h = new Handler(){
  2. @Override public void handleMessage(Message msg){
  3. switch(msg.what){
  4. case 1:
  5. // what you want when complete
  6. break;
  7. default:
  8. break;
  9. }
  10. }
  11. }
  12. MyThread thread = new MyThread(new Messenger(h));
  13. thread.start();

Now add this in your thread file.

  1. public class MyThread{
  2. Messenger m;
  3. public MyThread(Messenger m){
  4. this.m = m;
  5. }
  6. public void run(){
  7. super.run();
  8. // your codes
  9. //
  10. //when your task complete
  11. Message msg = Message.obtain();
  12. msg.what = 1;
  13. msg.obj = &quot;&quot;;
  14. try{
  15. m.send(msg);
  16. }catch(IOException e){
  17. e.printStackTrace();
  18. }
  19. }
  20. }

huangapple
  • 本文由 发表于 2020年9月20日 22:45:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63980194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定