ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android/Java] 스레드(Thread)와 핸들러(Handler)
    Android/Java 2022. 3. 18. 13:09
    반응형

    [모든 포스팅은 개인적 공부를 위해 작성된 글입니다]

     

    <스레드(Thread)란?>

    - 동시 수행이 가능한 작업 단위

    - 현재 수행 중인 작업 외의 기능을 동시에 처리할 때 사용

     - ex) 네트워킹 수행 시

      - 네트워킹의 경우 대기 시간이 길어지므로 처리와 동시에 UI도 멈춤 상태로 있게 되는 문제 발생

      - 이전에는 스레드 사용을 권장사항으로 여겼지만, 현재 버전에서는 반드시 사용해야 하는 것으로 변경되었음(사용하지 않는 경우 네트워킹 기능 자체가 동작하지 않음)

     

    <멀티 스레드 방식>

    - 하나의 프로세스 안에서 여러 개의 작업이 동시 수행됨

    - 같은 프로세스 안에서 메모리 리소스 공유하여 효율적인 처리 가능

     - 단, 동시에 리소스에 접근 시 데드락(DeadLock) 발생할 수 있음

    *데드락(DeadLock) - 여러 개의 스레드가 동시에 공통으로 사용하는 메모리 리소스에 접근했을 때 어떤 것을 먼저 처리할지 판단할 수 없어 발생하는 문제*

     

    <메인 스레드(Main Thread)>

    - 다른 말로 UI(User Interface) Thread 라고도 함

     - 사용자의 input을 받는 스레드

    - 절대 정지시킬 수 없음

     - 정지 || 종료 시키면 더이상 사용자의 input을 받을 수 없으므로

     - 정지시키면 앱이 종료됨

    - 안드로이드에서 UI를 처리할 때 사용되는 기본 스레드

    - 메인 스레드에서 이미 UI에 접근하고 있으므로 새로 생성한 다른 스레드에서는 핸들러(Handler) 객체를 사용해서 메인 스레드로 메시지를 전달함으로써 메인 스레드에서 처리하도록 만들 수 있음

    *핸들러(Handler) - 데드락 문제 해결을 위해 각 스레드 안에서 작업을 순서대로 처리하도록 함*

     

    *UI 변경은 반드시 메인 스레드에서만 이루어져야 함*

    - 안드로이드에는 크게 두 종류의 스레드가 있는데 Main Thread(UI Thread)와 Worker Thread가 있음

    - Main Thread

     - 어플리케이션을 실행하면 기본적으로 실행되는 스레드

     - UI 업데이트 담당

     - 시간이 오래 걸리는 작업을 하기에는 부적합(ex 네트워크, DB 작업)

      - 시간이 오래 걸리는 작업을 수행하면 그 작업이 완료되기 전까지는 UI가 멈춰 있을 것이므로 사용자에게 좋지 않은 사용 경험을 주게 됨(다른 작업들이 같은 자원을 붙잡고 있으면 ANR(Application Not Responding) 발생 가능성도 있음)

    - Worker Thread

     - 특정 목적을 위해 따로 생성하여 사용하는 스레드(ex 네트워크, DB 작업)

     

    <스레드 생성 방법>

    - 방법 1.

    new Thread(new Runnable() {
        @Override
        public void run() {
            //수행할 작업
        }
    }).start();

     - 스레드 이름을 따로 지정하지 않고 생성

     - 스레드가 할 일을 Runnable에 지정

     

    - 방법 2.

    class insert_thread extends Thread{
        @Override
        public void run() {
            super.run();
        }
    }
    insert_thread thread = new insert_thread();
    thread.start();

     

    <Looper>

    - 하나의 스레드는 하나의 Looper 가짐

    - 하나의 Looper는 하나의 스레드 담당

    - 어플리케이션이 실행되면(MainActivity가 실행되면) 자동으로 메인 스레드에 존재하는 Looper 돌기 시작

    - 내부에 Message Queue 존재

     - 무한 루프를 돌면서 Meesage Queue에 있는 메시지를 하나씩 Handler에 전달

     

    <메시지(Message)>

    - 메시지 객체에 Runnable 객체 또는 Message 객체가 존재

    - Lopper로 메시지 전달하는 경우

     - 메시지 객체에 Message 객체 존재하는 경우 sendMessage() 통해 전달

     - 메시지 객체에 Runnable 객체 존재하는 경우 post 통해 전달

    - Looper로부터 메시지 받는 경우

     - 메시지 객체에 Message 객체 존재하는 경우 handleMessage() 통해 메시지 받고 작업 수행

     - 메시지 객체에 Runnable 객체 존재하는 경우 해당 Runnable 객체의 run() 호출하여 수행

     

    <핸들러와 Looper 사용법>

    - 방법 1(deprecated 됨).

     - deprecated 된 이유

       - Handler가 담당할 Looper 지정하지 않아(Handler가 암시적으로 Looper 선택) 특정 작업 손실, 충돌 등의 문제가 발생할 수 있음

    new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            //Handler 생성
            Looper.loop();
        }
    }).start();

     - Looper.prepare()

      - 해당 스레드에 종속되는 Looper, MessageQueue 준비하고 Handler 생성

      - Handler 생성과 동시에 Looper와 Handler가 연결됨

      - 스레드의 run() 메서드 마지막에서 Looper.loop() 호출하여 Message 기다림

     

    - 방법 2.

     - Looper 명시

    new Thread(new Runnable() {
        @Override
        public void run() {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    
                }
            });
        }
    }).start();

     - Looper.getMainLooper()를 통해 메인 스레드의 Looper 사용할 것이라고 명시

     - Looper를 사용하였으므로 UI 변경 가능

     

    반응형

    댓글

Designed by Tistory.