취소와 타임아웃 #3
목차
Job에 대해 취소
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope {
val job1 = launch {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
val job2 = launch {
println("launch2: ${Thread.currentThread().name}")
println("1!")
}
val job3 = launch {
println("launch3: ${Thread.currentThread().name}")
delay(500L)
println("2!")
}
delay(800L)
job1.cancel()
job2.cancel()
job3.cancel()
println("4!")
}
fun main() = runBlocking {
doOneTwoThree()
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
job1은 1000ms 동안 지연 되기 때문에 3!은 출력이 안됨.
취소 불가능한 Job
launch(Dispatchers.Default)는 다른 스레드에서 수행 됨.
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
delay(200L)
job1.cancel()
println("doCount Done!")
}
fun main() = runBlocking {
doCount()
}
doCount Done!이 작업이 끝나기 전에 출력이 됨.
실제 job1이 취소가 되지 않음.
cancel과 join
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
delay(200L)
job1.cancel()
job1.join()
println("doCount Done!")
}
fun main() = runBlocking {
doCount()
}
cancel 이후에 join을 넣으면 doCount가 끝날 때 doCount Done!가 출력 됨.
cancelAndJoin
cancel을 하고 join을 하는 일은 자주 일어나는 일이기 때문에 한번에 하는 cancelAndJoin이 준비되어 있음.
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
delay(200L)
job1.cancelAndJoin()
println("doCount Done!")
}
fun main() = runBlocking {
doCount()
}
isActive
isActive를 호출하면 해당 코루틴이 여전히 활성화된지 확인이 가능.
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10 && isActive) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
delay(200L)
job1.cancelAndJoin()
println("doCount Done!")
}
fun main() = runBlocking {
doCount()
}
finally를 같이 사용
suspend 함수들은 JobCancellationException를 발생하기 때문에 표준 try catch finally로 대응할 수 있음.
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope {
val job1 = launch {
try {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
} finally {
println("job1 is finishing!")
}
}
val job2 = launch {
try {
println("launch2: ${Thread.currentThread().name}")
delay(1000L)
println("1!")
} finally {
println("job2 is finishing!")
}
}
val job3 = launch {
try {
println("launch3: ${Thread.currentThread().name}")
delay(1000L)
println("2!")
} finally {
println("job3 is finishing!")
}
}
delay(800L)
job1.cancel()
job2.cancel()
job3.cancel()
println("4!")
}
fun main() = runBlocking {
doOneTwoThree()
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
취소 불가능한 블록
어떤 코드는 취소가 불가능해야 함.
withContext(Noncancellable) 을 이용하면 취소 불가능한 블록을 만들 수 있음.
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope {
val job1 = launch {
withContext(NonCancellable) {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
delay(1000L)
print("job1: end")
}
val job2 = launch {
withContext(NonCancellable) {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("1!")
}
delay(1000L)
print("job2: end")
}
val job3 = launch {
withContext(NonCancellable) {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("2!")
}
delay(1000L)
print("job3: end")
}
delay(800L)
job1.cancel()
job2.cancel()
job3.cancel()
println("4!")
}
fun main() = runBlocking {
doOneTwoThree()
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
타임 아웃
일정 시간이 끝난 후 종료하고 싶으면 withTimeout을 사용.
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10 && isActive) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
}
fun main() = runBlocking {
withTimeout(500L) {
doCount()
}
}
취소가 되면 TimeoutCancellationException 예외가 발생
withTimeoutOrNull
import kotlinx.coroutines.*
suspend fun doCount() = coroutineScope {
val job1 = launch(Dispatchers.Default) {
var i = 1
var nextTime = System.currentTimeMillis() + 100L
while (i <= 10 && isActive) {
val currentTime = System.currentTimeMillis()
if (currentTime >= nextTime) {
println(i)
nextTime = currentTime + 100L
i++
}
}
}
}
fun main() = runBlocking {
val result = withTimeoutOrNull(500L) {
doCount()
true
} ?: false
println(result)
}
성공할 경우 withTimeoutOrNull의 마지막에서 true를 리턴하고, 실패했을 경우 null을 반환
'Book & Lecture > FastCampus' 카테고리의 다른 글
| 스코프 빌더, 잡 #2 (0) | 2022.04.15 |
|---|---|
| 스코프 빌더 #1 (0) | 2022.04.14 |
| 코루틴 등장 #0 (0) | 2022.04.14 |
| 대용량 서비스를 위한 아키텍처 with Redis #0 (0) | 2021.11.29 |