lifecycle ?

์žก๊ณผ ๋””ํผ๋“œ

๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋‹ด๊ณผ ๊ฐ™์ด ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฒฐ๊ณผ๊ฐ€ ์—†๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜ : ์ผ๋ฐ˜์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๊ณ  ๋ถ„์„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด ์ด๋Ÿฐ ์œ ํ˜•์— ์†ํ•œ๋‹ค.

  • ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜ : ์˜ˆ๋ฅผ ๋“ค์–ด ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ์›น ์„œ๋น„์Šค์—์„œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ ์ž ํ•  ๊ฒƒ์ด๋‹ค.

์žก

์žก์€ ํŒŒ์ด์–ด-์•ค-ํฌ๊ฒŸ(fire and forget)์ž‘์—…์ด๋‹ค. ํ•œ ๋ฒˆ ์‹œ์ž‘๋œ ์ž‘์—…์€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”ํ•œ ๋Œ€๊ธฐํ•˜์ง€ ์•Š๋Š”๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch {
				// Do background task here
		}
} 

์˜ˆ์™ธ ์ฒ˜๋ฆฌ

๊ธฐ๋ณธ์ ์œผ๋กœ ์žก ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋Š” ์žก์„ ์ƒ์„ฑํ•œ ๊ณณ๊นŒ์ง€ ์ „ํŒŒ๋œ๋‹ค. ์žก์ด ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋ฐœ์ƒํ•œ๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch {
				// TODO("Not Implemented!")
		}

		delay(500)
} 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ํฌ์ฐฉ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ์— ์˜ˆ์™ธ๊ฐ€ ์ „ํŒŒ๋œ๋‹ค.

๋ผ์ดํ”„ ์‚ฌ์ดํด

๋‹ค์Œ์€ ์žก์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๋ณด์—ฌ์ฃผ๋Š” ๋‹ค์ด์–ด๊ทธ๋žจ์ด๋‹ค.

  • New(์ƒ์„ฑ) : ์กด์žฌํ•˜์ง€๋งŒ ์•„์ง ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ์žก

  • Active(ํ™œ์„ฑ) : ์‹คํ–‰ ์ค‘์ธ ์žก. ์ผ์‹œ ์ค‘๋‹จ๋œ ์žก๋„ ํ™œ์„ฑ์œผ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.

  • Completed(์™„๋ฃŒ ๋จ) : ์žก์ด ๋” ์ด์ƒ ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

  • Canceling(์ทจ์†Œ ์ค‘) : ์‹คํ–‰ ์ค‘์ธ ์žก์—์„œ cancel()์ด ํ˜ธ์ถœ๋˜๋ฉด ์ทจ์†Œ๊ฐ€ ์•ˆ๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ธฐ๋„ ํ•œ๋‹ค. ์ด๊ฒƒ์€ ํ™œ์„ฑ๊ณผ ์ทจ์†Œ ์‚ฌ์ด์˜ ์ค‘๊ฐ„ ์ƒํƒœ๋‹ค.

  • Cancelled(์ทจ์†Œ ๋จ) : ์ทจ์†Œ๋กœ ์ธํ•ด ์‹คํ–‰์ด ์•ˆ๋ฃŒ๋œ ์žก. ์ทจ์†Œ๋œ ์žก๋„ ์™„๋ฃŒ๋กœ ๊ฐ„์ค„๋  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์„ฑ

์žก์€ ๊ธฐ๋ณธ์ ์œผ๋กœ launch()๋‚˜ Job()์„ ์‚ฌ์šฉํ•ด ์ƒ์„ฑ๋  ๋•Œ ์ž๋™์œผ๋กœ ์‹œ์ž‘ํ•œ๋‹ค. ์žก์„ ์ƒ์„ฑํ•  ๋•Œ ์ž๋™์œผ๋กœ ์‹œ์ž‘๋˜์ง€ ์•Š๊ฒŒ ํ•˜๋ ค๋ฉด CoroutineStart.LAZY๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
				// TODO("Not Implemented!")
		}

		delay(500)
} 

ํ™œ์„ฑ

์ƒ์„ฑ ์ƒํƒœ์— ์žˆ๋Š” ์žก์€ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ start()๋‚˜ join()์„ ํ˜ธ์ถœํ•ด์„œ ์‹คํ–‰ํ•˜๋Š”๋ฐ, ๋‘˜์˜ ์ฐจ์ด์ ์€ ์ „์ž์˜ ๊ฒฝ์šฐ ์žก์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์žก์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ˜๋ฉด ํ›„์ž๋Š” ์žก์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ์ผ์‹œ ์ค‘๋‹จํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
				// TODO("Not Implemented!")
		}

		job.start() // start๋Š” ์‹คํ–‰์„ ์ค‘๋‹จํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ suspend ํ•จ์ˆ˜๋‚˜ ์ฝ”๋ฃจํ‹ด์—์„œ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. 
		job.join() // join์€ ์‹คํ–‰์„ ์ผ์‹œ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฝ”๋ฃจํ‹ด ๋˜๋Š” ์ผ์‹œ ์ค‘๋‹จ ํ•จ์ˆ˜์— ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. 
} 

์ทจ์†Œ ์ค‘

์ทจ์†Œ ์š”์ฒญ์„ ๋ฐ›์€ ํ™œ์„ฑ ์žก์€ ์ทจ์†Œ ์ค‘์ด๋ผ๊ณ  ํ•˜๋Š” ์Šคํ…Œ์ด์ง• ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
				// TODO("Not Implemented!")
		}

		job.cancel()
		job.cancel(cause = Exception("Timeout!")) // ์˜ˆ์™ธ๊ฐ€ ์ทจ์†Œ์˜ ์›์ธ์ผ ๋•Œ๋Š” ์›์ธ์„ ๊ฐ™์ด ์ œ๊ณตํ•ด ์ฃผ๋ฉด ๋‚˜์ค‘์— ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.  
} 

์ทจ์†Œ ๋จ

์ทจ์†Œ ๋˜๋Š” ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ๋กœ ์ธํ•ด ์‹คํ–‰์ด ์ข…๋ฃŒ๋œ ์žก์€ ์ทจ์†Œ๋จ์œผ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค. ์žก์ด ์ทจ์†Œ๋˜๋ฉด, getCancellationException() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ทจ์†Œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
				// TODO("Not Implemented!")
		}

		job.cancel()
		
		val cancellation = job.getCancellationException()
		printf(cancellation.message)
}

์ทจ์†Œ๋œ ์žก๊ณผ ์˜ˆ์™ธ๋กœ ์ธํ•ด ์‹คํŒจํ•œ ์žก์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด CoroutineExceptionHandler๋ฅผ ์„ค์ •ํ•ด ์ทจ์†Œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val exceptionHandler = CoroutineExceptionHandler {
				_: CoroutineContext, throwable: Throable ->
				println("Job cancelled due to ${throwable.message}")	
		}

		GlobalScope.launch(exceptionHandler) {
				// TODO("Not Implemented!")
		}

		delay(2000)
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด invokeOnCompletion()์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

fun main(args: Array<String>) = runBlocking {
		GlobalScope.launch {
				// TODO("Not Implemented!")
		}.invokeOnCompletion { cause ->
				case?.let {
						println("Job cancelled due to ${it.message}")
				}
		}

		delay(2000)
}

์žก์˜ ํ˜„์žฌ ์ƒํƒœ ํ™•์ธ

์žก์—๋Š” ์ƒํƒœ๊ฐ€ ๋งŽ์•„์„œ ์™ธ๋ถ€์—์„œ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•œ๋‹ค.

  • isActive : ์žก์ด ํ™œ์„ฑ ์ƒํƒœ์ธ์ง€ ์—ฌ๋ถ€. ์žก์ด ์ผ์ง€ ์ค‘์ง€์ธ ๊ฒฝ์šฐ๋„ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • isCompleted : ์žก์ด ์‹คํ–‰์„ ์™„๋ฃŒํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€

  • isCancelled : ์žก ์ทจ์†Œ ์—ฌ๋ถ€. ์ทจ์†Œ๊ฐ€ ์š”์ฒญ๋˜๋ฉด ์ฆ‰์‹œ true๊ฐ€ ๋œ๋‹ค.

์†์„ฑ ์ •๋ณด

์ƒํƒœ(State)
isActive
isCompleted
isCancelled

์ƒ์„ฑ๋จ(Created)

false

false

false

ํ™œ์„ฑ(Active)

true

false

false

์ทจ์†Œ์ค‘(Cancelling)

false

false

true

์ทจ์†Œ๋จ(Cancelled)

false

true

true

์™„๋ฃŒ๋จ(Completed)

false

true

false

๋””ํผ๋“œ

๋””ํผ๋“œ(Deffered)๋Š” ๊ฒฐ๊ณผ๋ฅผ ๊ฐ–๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์žก์„ ํ™•์žฅํ•œ๋‹ค.

๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋Š” Future ๋˜๋Š” Promise๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์˜ ์ฝ”ํ‹€๋ฆฐ ๊ตฌํ˜„์ฒด๊ฐ€ ๋””ํผ๋“œ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ์ฝ˜์…‰ํŠธ๋Š” ์—ฐ์‚ฐ์ด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋ฉฐ, ๊ฐ์ฒด๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋น„์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

fun main(args: Array<String>) = runBlocking {
		val headlinesTask = GlobalScope.async {
				getHealines
		}

		headlinesTask.await()
}

์˜ˆ์™ธ ์ฒ˜๋ฆฌ

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

fun main(args: Array<String>) = runBlocking {
		val deffered = GlobalScope.async {
				TODO("Not implemented yet!")
		}
		try {
				headlinesTask.await()
		} catch (throwable: Throable) {
				println("Deferred cancelled due to ${throwable.message}")
		}
}

์š”์•ฝ

  • ์žก(Job)์€ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์— ์‚ฌ์šฉ๋œ๋‹ค.

  • ๋””ํผ๋“œ(Deferred)๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด ์ˆ˜์‹ ํ•˜๋ ค๋Š” ๊ฒƒ์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

  • ์žก์€ ๋‹ค์–‘ํ•œ ์ƒํƒœ๊ฐ’์„ ๊ฐ–๋Š”๋‹ค: ์ƒ์„ฑ(New), ํ™œ์„ฑ(Active), ์ทจ์†Œ ์ค‘(Canceling), ์ทจ์†Œ๋จ(Cancelled) ๋ฐ ์™„๋ฃŒ๋จ(Completed)

  • ์žก์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด isActive, isCancelled ๋ฐ isCompleted ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋””ํผ๋“œ๋Š” ์žก์„ ํ™•์žฅํ•ด ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฐ€๋Šฅ์„ฑ์„ ๋†’์ธ๋‹ค.

  • ๋””ํผ๋“œ๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋Š” ์žก์˜ ์ƒํƒœ์™€ ๊ฐ™๋‹ค

  • ์žก์˜ ์ƒํƒœ๋Š” ์•ž์œผ๋กœ๋งŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์ „ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋‹ค.

  • ์ตœ์ข… ์ƒํƒœ(final states)๋Š” ์žก์ด ์ด๋™ํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ ์ค‘ ํ•˜๋‚˜๋‹ค.

  • ์žก์˜ ์ตœ์ข… ์ƒํƒœ๋Š” ์ทจ์†Œ๋จ(Cancelled) ๋ฐ ์™„๋ฃŒ๋จ(Completed)์ด๋‹ค.

  • join()์„ ์‚ฌ์šฉํ•ด ๋””ํผ๋“œ๊ฐ€ ๋Œ€๊ธฐ๋œ ๊ฒฝ์šฐ, ์˜ˆ์™ธ๊ฐ€ ์ „ํŒŒ๋˜์ง€ ์•Š๋„๋ก ๊ฐ’์„ ์ฝ๊ธฐ ์ „์— ์ทจ์†Œ๋๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

  • ํ•ญ์ƒ ์žก์— ์˜ˆ์™ธ๋ฅผ ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜ ํ‘œ์‹œํ•˜์ž

Last updated

Was this helpful?