태그 보관물: 스레드

자바로 다중 작업(Multi Task)을 효과적으로 처리하는 방법들

자바로 다중 작업(Multi Task)을 효과적으로 처리하는 방법을 살펴보자. 자바에서 다중 작업을 처리하는데 기본으로 Thread 클래스와 Runnable 인터페이스를 사용한다. 하지만 이 Thread나 Runnable의 경우에는 병행처리를 하는 데 필요한 태스크 관리와 태스크의 분리(Divide)와 처리를 직접 구현해야 하는 단점이 있다. 그래서 자바 java.util.concurrent 패키지에는 다중 작업을 효과적으로 처리할 방법을 여러 가지 제공한다.

1. Executor 프레임웍

이 프레임웍은 처리해야 할 작업을 프로듀서-컨슈머 패턴의 큐에 저장하고, N개의 스레드를 사용해서 병행으로 처리하는 프레임웍이다. 일반적으로 프로듀스는 큐에 작업을 추가하고, 스레드 풀(컨슈머 스레드)에서 작업을 처리한다.

2. 카운트다운래치(CountDownLatch) & 사이클릭배리어(CyclicBarrier)

카운트다운래치(CountDownLatch)와 사이클릭배리어(CyclicBarrier)는 둘 다 큰 작업을 작은 작업으로 분리(개별 구현)하고, 이 분리한 작업의 실행을 완료한 뒤에 흐름을 진행하도록 흐름을 동기화시키는 클래스이다.
그림에서 보듯이, 카운트다운래치는 메인 스레드에서 작업을 처리하는 실행하는 스레드를 만들고 실행한다. 그리고 개별 스레드가 카운트다운래치의 값을 하나씩 제거하면, 메인 스레드가 시그널을 받아서 흐름을 진행하는 형태이다.

사이클릭배리어는 두 스레드 사이에 로직을 동기화하는 데 사용한다. 그래서 배리어를 사용해서 N개의 스레드 실행 흐름을 중단하다가, 배리어액션(단계를 지날 수 있는 과정)을 완료하면 N개의 스레드 실행 결과를 병합할 수 있는 형태이다. 그리고, 두 개의 스레드가 데이터를 교환하는데 사용하는 Exchanger는 사이클릭배리어의 특정 예이다.

3. ForkJoin 프레임웍

포크조인(ForkJoin) 프레임웍은 작업을 분리(분리하기 쉽게 선언)하고, 실행하고, 그리고 결과를 병합하기 쉽게 도와준다. 포크(Fork)는 작업을 분리하고, 조인(Join)은 분리한 작업이 완료한 뒤에 결과를 병합하는 과정이다. 이 프레임웍에 대한 자세한 내용은 http://www.oracle.com/technetwork/articles/java/fork-join-422606.html 에서 살펴보자.

이 그림에서 보듯이, 작업은 내부에서 fork()로 작업을 분리하고, join()으로 태스크를 병합한다. 그리고 이 작업은 재귀(Recursive)로 작업을 분리하는 형태라서 RecursiveTask 클래스를 상속해서 구현한다.

이제 어느 상황에서 이런 다중 작업을 처리하는 것이 좋은지 살펴보자.

1. 작업이 분리되지 않는 경우 “Executor”를 사용하자.

– 가장 많이 사용하는 형태이다.

2. 작업이 분리되는 경우에는 “카운트다운래치” 또는 “포크조인”을 사용하자.

– 많은 양의 데이터 정렬, 최대, 최소값 찾는 경우.
– 많은 양의 데이터를 합산하는 경우.
– 네트웍을 스캔하는 경우.
– 기타
개인적으로는 카운트다운래치를 많이 사용했지만, 작업 분리는 동일하지만 스레드 관리가 불편하다. 그래서 포크조인을 사용하는 것이 좋겠다.

3. 작업이 분리될 수도 있고 아닐 수도 있는 단계가 있는 작업은 “사이클릭배리어”를 사용하자.

– 예를 들어서 게임의 단계를 배리어도 두고 여러 스레드의 작업을 제어할 수 있다. 1단계를 지나면서, 랭킹정보, 개인정보, 게임정보등등을 가져오는 스레드를 실행하고, 필요한 정보를 다 가져온 뒤에 화면을 넘기는 예로 사용할 수 있겠다.

안드로이드 멀티스레딩

오늘 안드로이드 멀티스레딩 책을 선물 받았다. 이 책의 제목은 “Efficient Android Threading” 이다. 번역서에 영문 제목을 그대로 사용하고 있어서 책을 받아 든 순간 원서인가? 라는 느낌을 살짝 받았다. 이 책의 제목을 굳이 번역해 보자면 “효율적인 안드로이드 스레드”라고 할 수 있겠다. 이 책의 제목만으로 안드로이드에서 스레드를 효율적으로 사용하는 기법에 대한 내용을 살펴볼 수 있을 것으로 기대하게 된다. 이 책은 처음 원서로 접했을 때도 관심이 있었고, 더욱이 같이 일하는 동료가 번역해서 더 기대하고 읽어보게 되었다.

이 책의 저자는 안데스 예란손(트위터)이고, 구글링 해보면 외부 활동을 많이 하신 분은 아닌듯 하다. 이 분의 유투브 발표영상(https://www.youtube.com/watch?v=_q12gb7OwsA)도 참고하면 좋겠다.

이 책은 2개의 파트로 크게 구분하고 있다. 첫 번째 파트는 안드로이드 프로세스와 스레드에 대한 기본 지식에 대한 내용을 살펴볼 수 있다. 두 번째 파트는 본격적으로 안드로이드 스레드와 사용방법 그리고 비교적 효율적인 방법에 대한 내용을 살펴볼 수 있다.

파트의 구성인 개별 장의 내용에 대해서 간략하게 살펴보면 다음과 같다.

1장에서 안드로이드를 구성하는 구성요소(액티비티, 브로드캐스트 리시버, 서비스, 컨텐트 프로바이더)를 살펴본다.

파트 1 : 기초
– 2~6장까지 구성되어 있고, 개별 장은 다음의 내용으로 구성되어 있다.
2장에서는 안드로이드 스레드의 기본인 자바에서 사용하는 스레드에 대해서 살펴본다. 자바 스레드에 대한 내용이 좀 부실해서 다른 책을 읽어서 잘 알아둘 필요가 있다.
3장에서는 안드로이드 프레임웍을 사용하는 앱이 사용하는 리눅스 프로세스와 스레드를 살펴본다.
4장에서는 스레드 간의 통신하는 방법으로 파이프, 공유 메모리 그리고 핸들러를 살펴볼 수 있다. 이 장에서 핸들러는 안드로이드 내부에서 일반 스레드가 UI 스레드에 데이터를 전달하는 기본 방법으로 자세히 알아둘 필요가 있다.
5장에서는 안드로이드 앱의 프로세스 간 통신 방법을 알 수 있다. RPC를 사용하는 방법
6장에서는 메모리 누수에 대한 내용을 살펴본다. 결론으로 내부 클래스는 정적으로 사용한다. 그리고 안드로이드 메모리 누수도 자바의 일반적인 메모리 누수와 같아서 자바의 메모리 누수에 대한 내용을 살펴볼 필요가 있다. 그리고 안드로이드에서 많이 발생하는 Bitmap의 메모리 누수에 대한 내용이 없는 게 아쉽다.

파트 2 : 비동기 기법
– – 7~15장까지 구성되어 있고, 개별 장은 다음의 내용으로 구성되어 있다.
7장에서는 스레드 생명주기에 대해서 살펴보고 있고, 액티비티와 프래그먼트에서 사용되는 스레드를 살펴볼 수 있다.
8장에서는 핸들러 스레드(HandlerThread)를 사용하는 형태를 확인할 수 있다.
9장에서는 Executor 프레임웍을 살펴보고 있다. 이 프레임웍은 자바 5.0에서 추가된 전형적인 생산자/소비자(Producer/Consumer) 패턴 처리를 쉽게 지원한다. 자바언어를 기본으로 동작하는 많은 환경(JVM위에서 동작하는 스크립트 언어 포함)도 병행(Concurrent) 처리를 위해서 Executor 프레임웍을 사용하기 때문에 개인적으로는 안드로이드 스레드를 이해하는데 가장 중요한 기술적 배경을 살펴볼 수 있다.
10장에서는 AsyncTask에 대한 내용을 살펴보고 있다. 이 클래스는 사용하기 편리해서 안드로이드 앱이 비동기로 태스크를 처리하는 데 가장 많이 사용되고 있다. 가장 많이 사용하고 있는 이 클래스는 잘 알아둘 필요가 있다.
11장에서는 서비스.
12장에서는 인텐트 서비스.
13장에서는 AsyncQueryHandler.
14장에서는 로더(Loader)를 살펴보자. 로더는 허니콤 이후에 추가된 클래스로 기존에 사용하던 비동기 태스크를 액티비티나 프레그먼트의 생명주기와 같이 연동해서 사용하는 방법에 대해서 살펴볼 수 있다.
15장에서는 비동기 기술을 어떻게 선택할 것인지를 확인할 수 있다. 이 장의 내용은 좀 추상적인 면이 있어서 안드로이드에서 여러 가지 스레드 사용을 경험해 보고 상황에 맞는 스레드를 사용하면 되겠다. 개인적으로는 로더와 AsyncTask를 같이 사용해서 비동기 태스크를 처리하는 걸 추천한다.

이 책의 장단점을 살펴보자.

장점
이 책은 앱을 더 잘 만들 수 있는 안드로이드 스레드의 기본과 +알파를 제공한다.
많은 안드로이드 책들이 UI를 기준으로 쓰여 있어서 UX를 잘 만들기 위한 성능 개선에 대한 내용은 쉽게 접하기 힘든 부분이라서 이 책에 대한 내용이 매우 좋다.

단점
안드로이드 스레드를 사용하는 기본 내용에 충실하게 내용을 기술하고 있다.
제목에 걸맞는 “효율적인 안드로이드 스레드”에 대한 내용은 약간 부족하지 않나 싶다.
편집이 약간 아쉽다.

이 책은 처음부터 읽는 것을 추천하지만, 개인적으로는 11, 12, 13 그리고 15장은 해당 구성요소를 사용하거나 AsyncQueryHandler를 사용하는 경우에 읽어봐도 무방할 것으로 본다.

이 책을 읽으시는 초보 개발자분은 자바 스레드 책과 같이 읽어보면 좋을 것 같다.
그리고, 중/고급의 개발자에게는 다시 한번 안드로이드 앱이 동작하는 프로세스/스레드에 대한 기본 지식과 안드로이드 스레드를 잘 사용하기 위한 지식을 다시 한번 생각해 볼 수 있어서 좋을 것 같다.