1 minute read

Multi-threading

Android의 multi-threading 환경에서 thread간 업무분담을 위해 Handler 개념을 사용하게 된다.

예를 들어 무거운 동작들은 main thread가 아닌 다른 thread에서 수행하고, main thread에서는 결과만 받아 사용하도록 설계한다. 이때 main thread와 다른 thread간에 Handler를 사용하게 된다.

Handler 컨셉은 Android에서 유래했지만, asynchronous messaging, event handling과 같은 일반적 프로그래밍 패턴에 기반한다. Handler는 결국 multi-threading 환경에서 race condition을 방지하고 thread 간의 안정성을 확보하기 위한 방안이다. 즉, multi-threading 환경에서 thread간 통신 방법이고, 일종의 IPC(Inter-Process Communication)이라고 볼 수 있는 듯 하다(Process와 Thread를 유사하게 생각했을 경우).

Android에서는 이를 위해 Handler - Looper - MessageQueue 의 세가지 개념을 사용한다.

하나의 thread 안에서 실행되는 MessageQueue와 Looper의 개념부터 살펴보자.

MessageQueue, Looper

MessageQueue는 하나의 thread에서 수행될 Message 또는 Runnable 들을 쌓아놓는 queue이다. Message와 Runnable은 ‘하나의 작업 단위’라고 보면 된다. Message는 data로, thread가 처리할 data이다. 이 data는 다른 thread에서 온 것일 수도 있고 자기 자신이 생성한 것일 수도 있다. Runnable은 해당 thread에서 실행될 메서드, 함수라고 보면 된다.

Looper는 이 하나의 MessageQueue를 가지고 Message와 Runnable들을 처리하는 무한루프이다.

Message, Runnable의 처리 방식이 조금 헷갈리는데, 예시를 들어보자.

  1. Message가 main thread의 MessageQueue에 추가된다. (main이든 thread2, thread3이든 어떤 thread나 이러한 Message를 생성할 수 있다.)
  2. main thread의 Looper가 queue에서 Message를 꺼내면, Handler의 handle Message()를 수행하여 처리한다.
  3. main thread의 Looper가 queue에서 Runnable 객체를 꺼내면, run()을 수행하여 해당 작업을 바로 시작한다.

여기서 Handler의 개념이 등장한다.

Handler

Handler는 Message와 Runnable 객체들을 처리하는 중간다리의 역할을 한다.

Handler의 역할을 크게 3가지로 구분해 볼 수 있다.

  1. 하나의 thread의 Message와 Runnable의 processing
  2. Message/Runnable을 다른 thread의 Looper의 MessageQueue로 전달
  3. 다른 thread가 보낸 Message/Runnable을 자신이 속해있는 thread의 MessageQueue로 enqueue

  4. 하나의 thread의 Message와 Runnable의 processing

    • Handler자신이 속해있는 thread의 Looper는 MessageQueue에서 Message/Runnable을 꺼낸다. 꺼내진 Message는 Handler의 handleMessage() 메서드로 전달되어 processing된다. Runnable은 Handler가 run() 메서드를 통해 processing을 진행한다.
  5. Message/Runnable을 다른 thread의 Looper의 MessageQueue로 전달

    • Message : sendMessage() 메서드를 이용해 특정 thread의 MessageQueue에 Message 객체를 전달한다.
    • Runnable : post() 메서드를 이용해 특정 thread의 MessageQueue에 runnable 객체를 전달한다.
  6. 다른 thread가 보낸 Message/Runnable을 자신이 속해있는 thread의 MessageQueue로 enqueue

    • 다른 thread가 sendMessage()로 보낸 Message, post()로 보낸 Runnable을 자신의 Looper -> MessageQueue로 enqueue한다. 실제 Message와 Runnable 객체를 받고 저장하는 것은 MessageQueue의 역할이다.

Handler가 thread사이에 공유되는것처럼 표현되지만, 실제 코드에서는 각 thread 마다 handler 객체가 생성되어야 한다. 결국 thread 하나마다 Handler 하나, Looper 하나, Looper 안에 MessageQueue 하나씩 들어있다고 보면 될 듯하다.

References

[Android] Looper & Handler 기초 개념 (velog.io)

안드로이드 Handler 알고 쓰자 (brunch.co.kr)

Leave a comment