ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • javaFX - 쓰레드 동시성(Platform.renLater() 메서드 )
    고급 JAVA/FX 2020. 5. 23. 12:41

    javaFX 쓰레드 동시성

     

     JavaFX UI는 스레드가 안전하지 않기 때문에 UI 를 생성하거나 변경하는 작업은

     

    JavaFX Application Thread가 담당하고, 다른 작은 스레드들은 UI를 생성하거나 변경할 수 없음.

     

    main 스레드가 Application 의 launch() 메서드를 호출하면서 생성된 JavaFX Application Thread는

     

    1. start() 메서드를 실행시키면서 모든 UI를 생성함

     

    2. 컨트롤에서 이벤트가 발생할 경우 컨트롤러의 이번트 처리 메서드를 실행

     


     

    * JavaFX Application 개발 시 주의할 점 : JavaFX Application Thread가 시간을 필요로 하는 작업은

     

    하지 않도록 하는 것입니다. 시간을 필요로 하는 작업을 하게 되면 그 시간 동안 UI는 반응하지 않고

     

    멈춰있는 상태가 되므로 다른 작업스레드를 생성해서 처리하는 것이 좋음.

     

    ex)

     

    파일을 읽고 쓰거나, 네트워크 상에서 더이터를 주고받을 때 시간이 얼마나 걸리는지 모르기

     

    때문에 작업 스레드를 생성해서 처리해야 함.

     

    *작업 스레드가 직접 UI를 변경 불가

     

    해결 방법

     

    1. Platform.runLater()를 이용하거나

     

    2. javafx.concurrent API인 Task or Service를 이용하면 된다.

     


    Platform.runLater() 메서드

     

    작업 스레드가 직접 UI를 변경 불가하므로 UI 변경이 필요하면 작업 스레드는

     

    UI 변경 코드를 Runnable로 생성하고 이 것을 매개값으로 Platform의 runLater() 정적 메서드를 호출.

     

    runLater()는 이벤트 큐에 Runnable을 저장하고 바로 리턴.

     

    이벤트 큐에 저장된 Runnable들은 저장된 순서에 따라 JavaFX Application Thread에 의해 하나씩 실행 처리되어

     

    UI 변경 작업을 함.

     

    runLater()는 지연 처리 라는 뜻. => 주어진 매개값을 Runnable이 바로 처리하는 것이 아니라

     

    이벤트 큐에 먼저 저장된 Runnable을 처리한 후 처리.

     


     

    예제) 작업 스레드가 0.1초 주기로 얻어낸 시간을 이용해 JavaFX Application Thread가 Label 컨트롤의

     

            text속성을 변경. Label은 UI요소 => 작업 스레드에서 setText()메서드로 text 속성값 변경 X

     

    FXML
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    
    
    <?import javafx.scene.layout.*?>
    
    <?import javafx.scene.control.*?>
    
    
    
    <AnchorPane xmlns:fx="http://javafx.com/fxml" prefHeight="100.0" prefWidth="200.0" 
    
    fx:controller="thisisjava.RootController">
    
       <children>
    
          <Label fx:id="lblTime" alignment="CENTER" layoutX="25.0" layoutY="15.0" 
    
          prefHeight="35.0" prefWidth="150.0" 
    
          style="-fx-background-color: black; -fx-text-fill: yellow; 
    
          -fx-font-size: 20; -fx-background-radius: 10;" text="00:00:00" />
    
         <Button fx:id="btnStart" layoutX="46.0" layoutY="63.0" text="start" />
    
          <Button fx:id="btnStop" layoutX="110.0" layoutY="63.0" text="stop" />
    
       </children>
    
     
    
    </AnchorPane>
    
    
    자바1)
    
    package thisisjava;
    
    
    
    import java.net.URL;
    
    import java.text.SimpleDateFormat;
    
    import java.util.Date;
    
    import java.util.ResourceBundle;
    
    
    
    import javafx.application.Platform;
    
    import javafx.event.ActionEvent;
    
    import javafx.fxml.FXML;
    
    import javafx.fxml.Initializable;
    
    import javafx.scene.control.Button;
    
    import javafx.scene.control.Label;
    
    
    
    public class RootController implements Initializable {
    
    @FXML private Label lblTime;
    
    @FXML private Button btnStart;
    
    @FXML private Button btnStop;
    
    
    private boolean stop;
    
    
    @Override
    
    public void initialize(URL location, ResourceBundle resources) {
    
    btnStart.setOnAction(event->handleBtnStart(event));
    
    btnStop.setOnAction(event->handleBtnStop(event));
    
    }
    
    
    public void handleBtnStart(ActionEvent e) {
    
    stop = false;
    
    Thread thread = new Thread() {
    
    @Override
    
    public void run() {
    
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    
    while(!stop) {
    
    String strTime = sdf.format(new Date());
    
    Platform.runLater(()->{
    
    lblTime.setText(strTime);
    
    });
    
    try { Thread.sleep(100); } catch (InterruptedException e) {}
    
    }
    
    };
    
    };
    
    thread.setDaemon(true);
    
    thread.start();
    
    }
    
    
    public void handleBtnStop(ActionEvent e) {
    
    stop = true;
    
    }
    
    }
    
    
    
    자바2)
    
    package thisisjava;
    
    
    
    import javafx.application.Application;
    
    import javafx.fxml.FXMLLoader;
    
    import javafx.scene.Parent;
    
    import javafx.scene.Scene;
    
    import javafx.stage.Stage;
    
    
    
    public class AppMain extends Application {
    
    @Override
    
    public void start(Stage primaryStage) throws Exception {
    
    Parent root = (Parent)FXMLLoader.load(getClass().getResource("root.fxml"));
    
    Scene scene = new Scene(root);
    
    
    primaryStage.setTitle("runLater()메서드");
    
    primaryStage.setScene(scene);
    
    primaryStage.show();
    
    }
    
    
    public static void main(String[] args) {
    
    launch(args);
    
    }
    
    }

    댓글

Designed by Tistory.