Java의 JavaFX와 Thread

zihooy·2023년 5월 9일
0

Java Programming

목록 보기
17/21
post-thumbnail

Java의 라이브러리 JavaFX에 Thread를 적용해보자.

🏹 Thread를 사용할 때 주의할 점 !

우선 Thread에 대해 아직 잘 모르다면 클릭 !

Thread 1과 Thread 2가 있다고 가정해보자.
이때 어떤 하나의 값을 Thread 1과 Thread 2에서 둘 다 다루게 된다면, 문제가 발생한다.

만약 두 Thread에서 데이터의 값을 갱신하는 코드가 있다고 가정하면,
Thread 1과 2중에서 어떤 것이 먼저 실행될지 모르기 때문에 데이터의 갱신이 의도대로 이루어지지 않는다.

이때 사용하는 것이 lock()과 unlock()이다.

이것을 사용하면 lock() -> 실행할 코드 -> unlock()이 될 동안에는 다른 Thread로 동작이 넘어가지 않는다.

그러나 lock() 이후 unlock()이 너무 오랜 시간 뒤에 실행된다면 이것 역시 문제가 될 수 있기 때문에 유의해서 사용해야 한다.

이를 실행하는 함수가 Platform.runLater()이다.
아래의 코드를 살펴보면, 위 함수를 사용하여 btn2의 데이터 갱신을 보장한다.

public class HelloApplication extends Application{
    @Override
    public void start(Stage arg0) throws Exception {
        //V(ertical)Box, H(orizontal) Box
        VBox root = new VBox();
        root.setPrefSize(400, 300); //px단위, 가로, 세로
        root.setSpacing(5); //버튼과 버튼 사이의 간격
        // --------------------

        Button btn1 = new Button("첫번째 버튼" );    //눌렀을 때 Thread1이 만들어지도록
        Button btn2 = new Button("두번째 버튼" );
        //눌렀을 때 btn2의 내용이 바뀌도록
        btn1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                System.out.println(1);
                btn2.setText("호랑이");
                new Thread() {
                    public void run() {
                        System.out.println(2);
                        //btn2.setText("호랑이");  //충돌, 이를 해결하기 위해 lock()이 필요하다.
                        //() -> {}: 람다 함수의 기본꼴
                        Platform.runLater(()->{
                            btn2.setText("호랑이");
                        });  //lock()과 같은 역할, 람다 함수 사용
                    }
                }.start();
            }
        });
        root.getChildren().addAll(btn1,btn2);

        // --------------------
        //적용하기 위해서는 scene을 만들어서 등록해야 한다.
        Scene scene = new Scene(root);

        //scene과 arg0 연결
        arg0.setScene(scene);
        arg0.setTitle("Hello Jihu");
        arg0.show();
    }
    public static void main(String[] args) {
        launch();
    }
}

🏹 Thread 및 객체를 전달하는 방법

만약 Thread 및 객체를 다른 class 전달하고 싶다면, 2가지 방법이 있다.
1) 인수로 전달하기
Thread t = new Tiger(btn2);와 같이 인수로 btn2를 전달하고,

    Tiger(Button btn){
        this.btn = btn;
    }

위 코드처럼 인수를 포함한 생성자를 주면 외부 class에서도 사용이 가능하다.

2) this를 통해 class 객체 전체를 넘겨버리기
Thread t = new Tiger(HelloApplication.this);
만약 전달할 변수가 너무 많다면 위 코드처럼 HelloApplication 전체를 넘겨버릴 수 있다.

    Tiger(HelloApplication hello) {
        this.hello = hello;
    }

마찬가지로 class 객체를 포함한 생성자를 작성하면 된다.

class Tiger extends Thread {
    Tiger(){}
    Button btn;
    HelloApplication hello;
    Tiger(Button btn){
        this.btn = btn;
    }
    Tiger(HelloApplication hello) {
        this.hello = hello;
    }
    
    @Override
    public void run() {
        Platform.runLater(()->{
            //btn.setText("호랑이");   //방법1
            hello.btn2.setText("호랑이");  //방법2, this 활용, btn2를 활용하기 위해서는 btn2를 멤버 변수로 변경해 주어야 함
        });
    }
}
public class HelloApplication extends Application{	//여기까지 했을 떄 hello에 error가 뜨는 이유: 추상 메소드를 구현하지 않아서

    Button btn1 = new Button("첫번째 버튼" );    //눌렀을 때 Thread1이 만들어지도록
    Button btn2 = new Button("두번째 버튼" );
    @Override
    public void start(Stage arg0) throws Exception {
        //V(ertical)Box, H(orizontal) Box
        VBox root = new VBox();
        root.setPrefSize(400, 300); //px단위, 가로, 세로
        root.setSpacing(5); //버튼과 버튼 사이의 간격
        // --------------------


        //눌렀을 때 btn2의 내용이 바뀌도록
        btn1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                System.out.println(1);
                btn2.setText("호랑이");
                //방법1: 인수로 전달하기
                //Thread t = new Tiger(btn2);

                Thread t = new Tiger(HelloApplication.this); //자기자신, class 객체를 넘겨버림

                t.start();
            }
        });
        root.getChildren().addAll(btn1,btn2);

        // --------------------
        //적용하기 위해서는 scene을 만들어서 등록해야 한다.
        Scene scene = new Scene(root);

        //scene과 arg0 연결
        arg0.setScene(scene);
        arg0.setTitle("Hello Jihu");
        arg0.show();
    }
    public static void main(String[] args) {
        launch();
    }
}
profile
thisIsZihooLog

0개의 댓글