들어가기 앞서

안드로이드 앱은, 자바의 멀티스레드 프로그래밍 모델을 준수해야합니다. 자바가 편하긴하지만 동시프로그램 처리, 데이터 일관성 유지, Task 시퀀스 설정등 복잡성이 증가하는 단점이 있습니다. 이는 개발자가 고려하여 최대한 복잡성은 줄이고 성능을 높일 수 있도록 구현해야할 것입니다.



스레드 기본사항

보통 안드로이드에서는, 하나의 스레드에서 실행하는 작업의 단위를 TASK라고 지칭합니다. 

스레드는 순차적으로 하나 또는 다수의 태스크를 실행할 수 있습니다.



실행

자바에서는 run method 안에서 태스크를 정의함으로 구현할 수 있다.


private class MyThreadTask implements Runnable{

   public void run(){

int j = 0; // 스레드에서의 지역스택에 저장됨.

   }

}


run() 메서드 안에서 호출되는 지역변수는 스레드의 지역 메모리 스택에 저장됩니다. 태스크의 실행은 Thread 객체생성과 start() 메서드 호출로 

실핼할 수 있습니다.


Thread myThread = new Thread(new MyThreadTask ());

myThread.start();


스레드의 지역데이터를 저장하는 전용메모리가 있습니다. 


CPU는 한번에 하나의 스레드 명령어를 처리할 수 있습니다.


스레드의 변경을 문맥교환, Context Switch라고 합니다.

하나의 프로세서에 동시에 실행되는 두개의 스레드를 코드와 그림으로 보시겠습니다.

Thread T1 = new Thread(new MythreadTask());

T1.start();

Thread T2 = new Thread(new MythreadTask());

T2.start();



스레드 T1 ------                   ------------

                        ||||(문맥교환시간)

스레드 T2                  ------                  -----


      시간


T1과 T2사이에는 CPU가 사용하는 문맥교환시간이 존재해서 T1이 끝나고 바로 T2가 실행되는게 아니라 약간의 문맥교환 오버헤드가 드는것을 확인하실 수 있습니다.(위에 |||| ) 




싱글 스레드 애플리케이션

각 앱은, 하나이상의 스레드를 가집니다. 또한, 사용자의 반응성을 고려해서 멀티스레드 환경으로 구현해야하는 경우도 존재합니다.



멀티스레드 애플리케이션

동작이 동시에 실행되는것으로 인식되도록 앱 코드를 여러코드 경로로 분할하는 애플리케이션입니다. 실행 스레드 수가 프로세서의 수를 초과하면 완벽한 동시성이 될수는 없습니다. 

멀티스레드는 필수적이긴하나 그에따른 복잡성 증가는 개발자가 풀어야 할 과제입니다.



자원소비증가

각 스레드는 지역변수등을 저장하는 전용 메모리영역을 할당받습니다. 프로세서 측면에서는 스레드 설정 및 해제, 문맥 교환에서 스레드를 저장하고 복원시, 오버해드가 생기게됩니다. 스레드가 많아질수록, 더많은 문맥교환이 일어나고 성능이 저하되게 됩니다.



복잡성 증가

코드를 분석하기 어려워집니다. 또한 실행에 불확실성을 가져다 줍니다.



데이터 불일치

두개의 스레드가 공유자원을 사용할 경우, 어떤 순서로 데이터를 접근하는지 알수없게됩니다. 하나의 공유변수를 두개의 스레드가 접근할때 경쟁조건에 노출되게 됩니다. 

그래서 공유변수에접근할때 다른스레드가 접근할수없도록, 원자영역을 만드는것이 필수적입니다. 자바에서 가장 동기화 메커니즘은 synchronized 키워드를 사용하면 되겠습니다.


ex_)

synchronized(this){

  sharedVal++;

}


+ Recent posts