Skip to content

Latest commit

ย 

History

History
421 lines (263 loc) ยท 14.4 KB

Thread , Handler , Looper.md

File metadata and controls

421 lines (263 loc) ยท 14.4 KB

Thread , Handler , Looper

Android์˜ Thread, Handler, Looper ์— ๋Œ€ํ•˜์—ฌ

์ž‘์„ฑ์ž : ๋ฐ•ํƒœ์ž„

Present Time : 2018โ€“06-03-SUN

Last Updated : 2018-



0. ๋“ค์–ด๊ฐ€๊ธฐ์ „,,

0.1 ์šฉ์–ด์ •๋ฆฌ

๋ฉ”์ธ ์Šค๋ ˆ๋“œ (UI ์Šค๋ ˆ๋“œ)

ํ”„๋กœ์„ธ์Šค์—์„œ ์ œ์ผ ์ฒ˜์Œ ์‹คํ–‰๋˜๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋งํ•œ๋‹ค. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” ์‘์šฉํ”„๋กœ๊ทธ๋žจ์˜ ์‹œ์ž‘๊ณผ ํ•จ๊ป˜ ์‹œ์ž‘๋˜๊ณ  ํ•ด๋‹น ์‘์šฉํ”„๋กœ๊ทธ๋žจ์˜ ํ”„๋กœ์„ธ์Šค์™€ ๊ฐ™์€ ์ˆ˜๋ช…์„ ๊ฐ€์ง„๋‹ค. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” UI๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์Šค๋ ˆ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— UI์Šค๋ ˆ๋“œ๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค. UI์Šค๋ ˆ๋“œ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํ™”๋ฉด UI์š”์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์‘์šฉํ”„๋กœ๊ทธ๋žจ์˜ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์ด๋‹ค.

์ž‘์—… ์Šค๋ ˆ๋“œ, ์„œ๋ธŒ ์Šค๋ ˆ๋“œ

๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ํŒŒ์ƒ๋˜์–ด ์‹คํ–‰๋˜๋Š” ์Šค๋ ˆ๋“œ


๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ

๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์Šค๋ ˆ๋“œ๋กœ ๋™์‹œ์— ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ์ด๋ผ ํ•œ๋‹ค. ์‹œ์Šคํ…œ ๋‚ด์—์„œ ํ•ด๋‹น ์ž‘์—… ๋˜๋Š” ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์—๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์‹คํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค. ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜์ง€ ๋ชปํ•œ (Thread-Unsafe) ๋ฉ”์†Œ๋“œ ๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค.

๋ทฐ๋‚˜ ๋ทฐ๊ทธ๋ฃน์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ์ด๋‹ค.


๋™๊ธฐํ™”(Synchronized)

ํ•˜๋‚˜์˜ ์ž์›์„ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•  ๋•Œ ํ•œ ์‹œ์ ์—์„œ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

Ex) ํ”„๋ฆฐํ„ฐ : ๋ฌธ์„œ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์žˆ๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ๋ฌธ์„œ๋ฅผ ๋™์‹œ์— ํ”„๋ฆฐํ„ฐ๋กœ ์ถœ๋ ฅํ•  ์ˆ˜ ์—†๋‹ค.



1. Thread

1.1 ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ์˜ ์Šค๋ ˆ๋“œ

์Šค๋ ˆ๋“œ๋ž€ ์‰ฝ๊ฒŒ ๋งํ•ด ์—ฌ๋Ÿฌ์ž‘์—…์„ ๊ฐ™์ด ํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์Œ์•…์„ ๋“ค์œผ๋ฉด์„œ SNS๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด๋‹ค.

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์„ฑ๋Šฅํ–ฅ์ƒ์„ ์œ„ํ•ด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€๋งŒ, UI๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ์ด ์ ์šฉ๋œ๋‹ค. ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋กœ UI๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋ฉด ๋™์ผํ•œ UI์ž์›์„ ์‚ฌ์šฉํ•  ๋•Œ *๊ต์ฐฉ ์ƒํƒœ, *๊ฒฝํ•ฉ ์ƒํƒœ ๋“ฑ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ UI์—…๋ฐ์ดํŠธ๋Š” ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ํ—ˆ์šฉํ•œ๋‹ค.


1.2 Thread, ์™œ ์‚ฌ์šฉํ•ด์š”?

๋ฉ”์ธ์Šค๋ ˆ๋“œ ๋งŒ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, ์‚ฌ์šฉ์ž๋Š” ํ•ด๋‹น ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋ฉˆ์ถฐ์žˆ๋Š” ํ™”๋ฉด์„ ๋ณด๊ณ ๋งŒ ์žˆ์–ด์•ผํ•œ๋‹ค. ์˜ค๋žœ ์‹œ๊ฐ„๋™์•ˆ UI๊ด€๋ จ ์ž‘์—…์ด ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•˜๋ฉด ๊ฒฐ๊ตญ *ANR ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ •์ง€๋œ๋‹ค.

์•ˆ๋“œ๋กœ์ด๋“œ 3.0 ๋ฒ„์ „๋ถ€ํ„ฐ ํ†ต์‹  ํด๋ž˜์Šค ๋‚ด ์ „์†ก์ด๋‚˜ ์ˆ˜์‹ ๊ณผ ๊ด€๋ จ๋œ ๋ฉ”์†Œ๋“œ๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์˜๋„์ ์œผ๋กœ ๋ง‰์•„๋ฒ„๋ ธ๋‹ค. EX) ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ์†Œ์ผ“ํด๋ž˜์Šค์˜ conntect() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด 'NetworkOnMainThreadException' ์ด ๋ฐœ์ƒํ•œ๋‹ค.

์œ„์™€๊ฐ™์€ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ๊ธฐ๋Šฅ์ด๋‚˜ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰, ๋นˆ๋ฒˆํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ํŒŒ์ผ์˜ ๋กœ๋“œ๊ณผ ๊ฐ™์ด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…๋“ค์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์—ฌ๋ถ„์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. (๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ)

์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์„ ์ œ๋Œ€๋กœ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์€ ํ•„์ˆ˜์ ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.


1.3 Thread, ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž

์Šค๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ํ•˜๋‚˜๋Š” Thread๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€ ํ•˜๋‚˜๋Š” Runnable์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

1.3.1 Thread๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•˜๊ธฐ

public class TaeiimThread extends Thread {
    @Override
    public void run() {
        super.run();
        // Do something..
    }
}
// ์Šค๋ ˆ๋“œ ์‹คํ–‰
TaeiimThread thread = new TaeiimThread();
thread.start();

1.3.2. Runnable ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„

Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ํ›„, run() ๋ฉ”์†Œ๋“œ์— ์›ํ•˜๋Š” ์ž‘์—…์„ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

์™„์„ฑ๋œ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„, Thread ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค.

public class TaeiimRunnable implements Runnable {
    @Override
    public void run() {
        // Do something,, 
    }
}
// ์‚ฌ์šฉํ•˜๊ธฐ 
TaeiimRunnable myRunnable = new TaeiimRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

1.3.3. Thread VS. Runnable

Thread์™€ Runnable ์€ ๋ช‡๊ฐ€์ง€ ์ฐจ์ด์ ์ด ์žˆ๋‹ค.

  1. Thread๋Š” ์ƒ์†(Extends)์„ ๋ฐ›๋Š” ๊ฒƒ์ด๋ฉฐ Runnable์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ์„œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ํฐ ์ฐจ์ด์ ์ด๋‹ค.

    ์ž๋ฐ”๋Š” ๋‹ค์ค‘ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— Thread๋ฅผ ์ƒ์†๋ฐ›๊ฒŒ ๋˜์€ ํด๋ž˜์Šค๋Š” ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์„ ์ˆ˜๊ฐ€ ์—†์ง€๋งŒ Runnable์€ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— implements๋งŒ ํ•˜๋ฉด ๋˜๊ณ  ๋‹ค๋ฅธ ํ•„์š”ํ•œ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

  2. Thread๋Š” ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ, Runnable ๊ฐ€๋Šฅ

    ์Šค๋ ˆ๋“œ๋Š” ์ผํšŒ์šฉ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ๋ฒˆ ์‚ฌ์šฉํ•œ ์Šค๋ ˆ๋“œ๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์žฌ์‚ฌ์šฉ์‹œ 'IllegalThreadStateException' ์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ฆ‰, ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•ด start()๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, Runnable๋กœ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.


์šฉ์–ด์ •๋ฆฌ

*๊ต์ฐฉ์ƒํƒœ(dead lock): ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ž‘์—…์ด ์„œ๋กœ ์ƒ๋Œ€๋ฐฉ์˜ ์ž‘์—…์ด ๋๋‚˜๊ธฐ ๋งŒ์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ์ ์œผ๋กœ ์•„๋ฌด๊ฒƒ๋„ ์™„๋ฃŒ๋˜์ง€ ๋ชปํ•˜๋Š” ์ƒํƒœ
*๊ฒฝํ•ฉ์ƒํƒœ(race condition) : ๋‘ ๊ฐœ ์ด์ƒ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ณตํ†ต ์ž์›์„ ๋ณ‘ํ–‰์ ์œผ๋กœ ์ฝ๊ฑฐ๋‚˜ ์“ธ ๋•Œ, ๊ณต์šฉ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ์–ด๋–ค ์ˆœ์„œ์— ๋”ฐ๋ผ ์ด๋ฃจ์–ด์กŒ๋Š”์ง€์— ๋”ฐ๋ผ ๊ทธ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ์ƒํ™ฉ
*ANR : ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ๋Š” ์–ด๋–ค ์ž‘์—…์„ ์š”์ฒญํ•˜๊ณ  5์ดˆ๊ฐ„์˜ ์‘๋‹ต์ด ์—†์„ ๋•Œ ๊ฐ•์ œ์ข…๋ฃŒ ์—ฌ๋ถ€๋ฅผ ๋ฌป๋Š” ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์ด ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ANR(Application not responding) ๋ฉ”์‹œ์ง€ ๋ผ๊ณ  ํ•œ๋‹ค.


2. Handler

2.1 Handler๋ž€?

Handler๋Š” Looper๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ Message๋ฅผ ์‹คํ–‰, ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„์„œ Message Queue์— ๋„ฃ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ์Šค๋ ˆ๋“œ ๊ฐ„์˜ ํ†ต์‹  ์žฅ์น˜์ด๋‹ค.

thread_img

ํ•ธ๋“ค๋Ÿฌ๋Š” ๋‘ ์ข…๋ฅ˜์˜ ๊ฐ์ฒด๋ฅผ **๋ฉ”์‹œ์ง€ ํ(Message Queue)**๋ฅผ ํ†ตํ•ด ํŠน์ • ์Šค๋ ˆ๋“œ๋กœ ์ „๋‹ฌํ•œ๋‹ค.

  1. ๋ฌธ์ž์™€ ํ•„๋“œ๋กœ ๊ตฌ์„ฑ๋œ ๋ฉ”์‹œ์ง€ ๊ฐ์ฒด
  2. Runnable ๊ฐ์ฒด

๋ฉ”์‹œ์ง€ํ๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ๋‚ด ์„œ๋ธŒ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค ๋‚ด ์กด์žฌํ•˜๋Š” ์Šค๋ ˆ๋“œ์— ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

ํ•ธ๋“ค๋Ÿฌ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฉ”์‹œ์ง€ํ๊ฐ€ ์ œ๊ณต๋˜๋Š” ์Šค๋ ˆ๋“œ์—์„œ ์ƒ์„ฑํ•ด์•ผํ•œ๋‹ค. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” ๊ธฐ๋ณธ์œผ๋กœ ๋ฉ”์‹œ์ง€ํ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.


2.2 ์‚ฌ์šฉ๋ชฉ์ 

ํ•ธ๋“ค๋Ÿฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ UI๊ฐฑ์‹ ์„ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

  1. ๋ฉ”์†Œ๋“œ๊ฐ€ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ์ผ ๋•Œ , Thread-Safe๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด

    ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด 'CalledFromWrongThreadException' ์ด๋ผ๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๊ฒƒ์€ ๋ทฐ ํด๋ž˜์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ(์—ฌ๊ธฐ์„œ๋Š” setText()) ๋ฅผ ๋ฉ”์ธ์Šค๋ ˆ๋“œ(UI ์Šค๋ ˆ๋“œ) ๊ฐ€ ์•„๋‹Œ ์„œ๋ธŒ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์‹œ์ผฐ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    0-2์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ๋ทฐ๋‚˜ ๋ทฐ๊ทธ๋ฃน์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ(Thread-Unsafe)์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

    public class TaeiimThread extends Thread {
        @Override
        public void run() {
            super.run();
            textView.setText("๋ฐ•ํƒœ์ž„ ์งฑ");  // Error!!
        }
    }

    ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด **์ž๋ฐ”๋Š” ๋™๊ธฐํ™”(Synchronized)**๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์•ˆ๋“œ๋กœ์ด๋“œ๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

    ์Šค๋ ˆ๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ๋“ฑ์˜ ์ž‘์—…๋“ค์„ ํ•˜๋Š” ๋„์ค‘์— UI๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.


  2. ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค์—์„œ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์˜ ํ•ธ๋“ค๋Ÿฌ์— ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜์—ฌ ์ž‘์—…์„ ์š”์ฒญํ•  ๋•Œ

    ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์Šค๋ ˆ๋“œ ์‚ฌ์ด์— ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ์ˆ˜๋‹จ์œผ๋กœ ๋ฉ”์‹œ์ง€ํ์™€ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฑ„ํƒํ–ˆ๋‹ค. ๋งŒ์•ฝ ์ผ๋ฐ˜ ์Šค๋ ˆ๋“œ์‚ฌ์ด์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ฃผ๊ณ  ๋ฐ›์œผ๋ ค๋ฉด ๋ฃจํผ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.


2.3 Handler, ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์ž!

๋‹ค์Œ์€ Handler๋ฅผ ์ด์šฉํ•ด 1์ดˆ์”ฉ ์ฆ๊ฐ€ํ•˜๋Š” ํƒ€์ด๋จธ๋ฅผ ๋งŒ๋“  ์˜ˆ์ œ์ด๋‹ค.

package com.example.parktaeim.threadex;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity{
    TextView timeTv;
    Button startBtn;

    Runnable timeRunnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        timeTv = (TextView) findViewById(R.id.timeTv);
        startBtn = (Button) findViewById(R.id.startBtn);

        startBtn.setOnClickListener(v->{
            // Runnable ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Thread ์ƒ์„ฑ
            Thread timeThread = new Thread(timeRunnable);   
            timeThread.start();  // Thread Start
        });

        timeRunnable = new Runnable() {
            @Override
            public void run() {
                int time = 0;
                while(true){
                    Message msg = new Message();
                    msg.what = 0;
                    msg.arg1 = time;
                    handler.sendMessage(msg);    // Handler์— Message ๋ณด๋ƒ„ 

                    try{
                        Thread.sleep(1000);
                        time++;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    }

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {    
            super.handleMessage(msg);
            if(msg.what == 0){   
                timeTv.setText(String.valueOf(msg.arg1));
            }
        }
    };
}


3. Looper

3.1 Looper๋ž€

Looper๋Š” ๋ฌดํ•œํžˆ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ์ž์‹ ํžˆ ์†ํ•œ ์Šค๋ ˆ๋“œ์˜ Message Queue์—์„œ Message๋‚˜ Runnable ๊ฐ์ฒด๋ฅผ ์ฐจ๋ก€๋กœ ๊บผ๋‚ด Handler๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ „๋‹ฌํ•œ๋‹ค.

๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—๋Š” Looper๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ์„ฑ๋˜์–ด ์žˆ์ง€๋งŒ, ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ์Šค๋ ˆ๋“œ๋Š” Looper๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์—†๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์‹œ์ง€ ํ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์„œ๋ธŒ ์Šค๋ ˆ๋“œ์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š” Looper๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.


3.2 ํŠน์ง•

  1. ๋ฃจํผ ํด๋ž˜์Šค๋Š” ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ •์  ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

    public final class Looper {
        ... ...
        //Looper ํด๋ž˜์Šค์˜ prepare(), loop() ๋“ฑ์˜ ๋ฉ”์†Œ๋“œ๋“ค์€ ์ •์  ๋ฉ”์†Œ๋“œ๋กœ ๋˜์–ด์žˆ๋‹ค. 
    	public static void prepare() {
     	   prepare(true);
    	}
    	public static void loop() {
    	 	......       
    	}
      
        ... ... 
    }
    // ๊ทธ๋ž˜์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 
    Looper.prepare();
    Looper.loop();

  2. ๋ฃจํผ๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฉ”์‹œ์ง€ํ์™€ ์—ฐ๊ฒฐ์‹œ์ผœ ์ค€๋‹ค.

    Looper.prepare(); ํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ์ˆœ์„œ

    public static void prepare() {
            prepare(true);
        }
    
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    // prepare(boolean quitAllowed) ๋ฉ”์†Œ๋“œ์—์„œ new Looper()
    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);   // MessageQueue ์—ฌ๊ธฐ์„œ ์ƒ์„ฑ
            mThread = Thread.currentThread();   
        }

3.3 ์‚ฌ์šฉํ•˜๊ธฐ

๋ฃจํผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๊ณ  ๊ฐ์ฒด ๋‚ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์ž๋ฐ” ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋‹ค๋ฅด๊ฒŒ

๋ฃจํผ ์ดˆ๊ธฐํ™” -> ํ•ธ๋“ค๋Ÿฌ ์ƒ์„ฑ -> ๋ฃจํผ ์‹คํ–‰ ์ด๋ผ๋Š” 3๋‹จ๊ณ„๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

public class LooperEx extends Thread {
    public Handler handler;

    @Override
    public void run() {
        Looper.prepare();   // Looper ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฉ”์‹œ์ง€ํ๋ฅผ ์ดˆ๊ธฐํ™”
        
        handler = new Handler(){    // ํ•ธ๋“ค๋Ÿฌ ๊ฐ์ฒด ์ƒ์„ฑ
            @Override
            public void handleMessage(Message msg) {
                // ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ 
            }
        };
      
        // ์Šค๋ ˆ๋“œ ๋‚ด ํ•ธ๋“ค๋Ÿฌ์— ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌ. ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜์ง€ ์•Š๋„๋ก ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ธฐ๋Šฅ.
        Looper.loop();   
    }
}


4. ๋งˆ๋ฌด๋ฆฌ

HandlerThread

๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Looper๊ฐ€ ์ œ๊ณต๋˜์ง€๋งŒ ์„œ๋ธŒ์Šค๋ ˆ๋“œ์—์„œ๋Š” Looper๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ€์ง€์ง€ ์•Š์•„ ์ง์ ‘ ์ƒ์„ฑํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ๋‹ค. ์ด์™€ ๊ฐ™์€ ๋ถˆํŽธํ•จ์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑํ•  ๋•Œ Looper๋ฅผ ์ž๋™์œผ๋กœ ๋ณด์œ ํ•œ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ HandlerThread์ด๋‹ค.

AsyncTask

ThreadPoolExecutor


UI ์—…๋ฐ์ดํŠธ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋“ค

์•ˆ๋“œ๋กœ์ด๋“œ๋Š” ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜์ง€ ๋ชปํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์ด์™ธ์—๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable) , View.postDelayed(Runnable, long)

์œ„์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UI๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‘ ๋ฉ”์†Œ๋“œ๋Š” ์—„๋ฐ€ํ•˜๊ฒŒ ์ด์•ผ๊ธฐํ•˜์—ฌ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋ฉฐ, ๋ชจ๋‘ Runnable ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•œ๋‹ค.


์ถœ์ฒ˜

๋„์„œ
  • ๊ฐ์ฒด์ง€ํ–ฅ ์›๋ฆฌ๋กœ ๋ฐฐ์šฐ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ (๋ฐ•ํ˜„์žฌ ์ง€์Œ) - 13์žฅ. ์Šค๋ ˆ๋“œ์™€ ํ•ธ๋“ค๋Ÿฌ
  • ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ Next Step (๋…ธ์žฌ์ถ˜ ์ง€์Œ) - 2์žฅ. ๋ฉ”์ธ์Šค๋ ˆ๋“œ์™€ Handler
  • ์™„๋ฒฝํ•œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์„ ๋งŒ๋“œ๋Š” ์‹ค๋ฌด ๋…ธํ•˜์šฐ 139 (๊ฐ€๋‚˜ ๋งˆ๋‚˜๋ถ€, ์˜ค์นด์ค€ ์™ธ 6๋ช… ์ง€์Œ, ์žฅ๋…๋Œ€ ์˜ฎ๊น€)
  • Efficient Android Threading, ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ (์•ˆ๋ฐ๋ฅด์Šค ์—๋ž€์† ์ง€์Œ, ํ•œ๋Œ€ํฌ ์˜ฎ๊น€)
์›น์‚ฌ์ดํŠธ