개발 업무를 몇년째 하고 있는데, 일부 개발자분들이 thread를 new Thread().start() 와 같이 단편적인 worker로만 사용하는 경우가 많이 있고, 백그라운드로 동작시키면서 queue 처리가 필요한 작업을 하려고 할때 thread pool을 만들고 pool size를 1로 해서 구현하는 경우가 있는가 하면, 내부에 lock, unlock, semaphore, flag 등을 동원하여 쓰레드를 제어하는 경우도 있다.


쓰레드는 잘 쓰면 참 좋은 도구이지만, 잘못 쓰면 디버깅도 힘들고 이슈가 발생하여도 재현도 잘 되지 않으며, 그리고 결정적으로 고치기는 매우 힘들다.


나는 플래그 사용하는 것도 싫어하고, 멤버 변수에 thread 변수를 생성하여 if thread가 생성되었나? 되었으면 blocking list에 insert 하는 구조도 좋아하지 않는다.


최근 업무로 구조를 새로 잡는 프로젝트가 있는데, 진짜 지옥 of 지옥이다.


개인적으로정리도 해둘겸해서 백그라운드 작업용도로 사용할 쓰레드를 Handler, Looper와 함께 사용하는 방법으로 정리해둔다.


두가지 방법이 있는데, 첫번째는 안드로이드의 Thread와 Handler 그리고 Looper를 직접 사용하는 방법이다.



Thread 를 상속받아 run 내부에 Looper 와 hanlder를 직접 사용하여 queued 백그라운드 처리를 할수 있다.


작업을 요청할때는 아래와 같이 요청하면 된다.



Hander에 메시지를 보내는것으로 작업요청은 끝이고, Handler에 의해서 작업요청이 queue에 의해서 하나씩 순차적으로 처리가된다.


데이터 정합성을 보장해야하는 경우 요청이 들어오는 순서대로 처리를 해야 정합성을 그마나 보장할수 있다. (반드시 해당 쓰레드 한군데에서만 데이터 베이스에 접속을 하는것도 빠지면 안된다.)



두번째 방법은 위와 같은 구현을 Android에서 제공하는 것이 있는데, 바로 HandlerThread이다.



작업을 요청하는 방법은 첫번째 방법과 다르지 않다.



Thread 관리를 위해서 별도로 구현한 ThreadMonitor와 ClosableThread인터페이스가 있는데, Looper.loop() 통한 무한루프를 가지고 있는 쓰레드이기 때문에 때문에 작업이 모두 끝나면 getLooper.quit() 등으로 looper를 종료시켜주어야 한다.


위에서 request시  thread 의 state를 관리하여 CountdDownLatch로 동시성 제어를 하는 이유는, 쓰레드가 생성되고 running 상태가 되고나서야 Handler를 통해서 메시지를 보내기 위해서이다.


실행결과는 다음과 같이 요청에 대해서 순차적으로 처리가 된다.



쓰레드 id를 보면 첫번째 구현으로 만든 SimpleThread는 32164 이고, 두번째 구현으로 만든 SimpleHandlerThread는 32163 이다.


이 둘의 쓰레드를 각각 모니터링하여 작업이 모두 끝나면 쓰레드를 종료시켜주기 위한 ThreadMonitor를 각각 생성하여 추가하였는데, 작업이 끝날때마다 onProcessed 를 전달받아 작업 요청사항들을 관리하고 종료가되면 쓰레드들을 종료시키는 기능을 한다.


플래그 사용하는 것을 싫어하기 때문에 사용하는 방법이기 때문에 아래 첨부한 소스를 참고하여 다른 방법으로 응용하여 사용하여도 좋을듯하다.


ClosableThread.java

MainActivity.java

Monitor.java

SimpleHandlerThread.java

SimpleThread.java

ThreadMonitor.java



블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,