การเก็บกวาดด้วย finally และ NonCancellable
คืนทรัพยากรใน coroutine ที่ถูกยกเลิกด้วย finally และ withContext(NonCancellable)
การเก็บกวาดด้วย finally และ NonCancellable เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
การยกเลิกและ finally
เมื่อโคโรทีนถูกยกเลิก จุดระงับการทำงานจะโยน CancellationException โค้ดในบล็อก finally จะทำงานเสมอ แต่ตัว finally เองจะทำงานในบริบทโคโรทีนที่ถูกยกเลิกแล้ว
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} finally {
println("finally: cleaning up")
}
}
delay(50)
job.cancel()
job.join()
}ปัญหา: การระงับการทำงานใน finally
หากพยายามใช้ delay หรือทำการระงับการทำงานอื่นภายใน finally ของโคโรทีนที่ถูกยกเลิก ระบบจะโยนข้อยกเว้นทันที เพราะบริบทถูกยกเลิกไปแล้ว
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} finally {
// delay(100) // throws CancellationException here!
println("Sync cleanup OK; async cleanup needs NonCancellable")
}
}
delay(50); job.cancel(); job.join()
}withContext(NonCancellable)
ครอบการเรียกที่มีการระงับการทำงานใน finally ด้วย withContext(NonCancellable) เพื่อให้การเรียกเหล่านั้นทำงานในบริบทที่ยกเลิกไม่ได้ แม้ขอบเขตแม่จะถูกยกเลิกแล้ว
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} finally {
withContext(NonCancellable) {
delay(100) // OK: runs despite cancellation
println("Async cleanup complete")
}
}
}
delay(50); job.cancel(); job.join()
}ควรใช้ NonCancellable เมื่อใด
ใช้ NonCancellable สำหรับการปิดการเชื่อมต่อฐานข้อมูล การเขียนบันทึกให้เสร็จ การส่งเหตุการณ์การวิเคราะห์ หรือการล้างข้อมูลแบบอะซิงโครนัสใด ๆ ที่ต้องทำให้เสร็จไม่ว่าจะถูกยกเลิกหรือไม่
import kotlinx.coroutines.*
suspend fun closeConnection() {
println("Closing DB connection...")
delay(50) // simulate async close
println("Connection closed")
}
fun main() = runBlocking {
val job = launch {
try { delay(1000) }
finally { withContext(NonCancellable) { closeConnection() } }
}
delay(50); job.cancel(); job.join()
}NonCancellable ไม่ใช่ขอบเขต
NonCancellable คือ Job ที่สามารถส่งให้ withContext ได้ อย่าใช้โดยตรงเป็นขอบเขตโคโรทีน แต่ให้ใช้เฉพาะในการล้างข้อมูลภายใน finally เท่านั้น
import kotlinx.coroutines.*
fun main() = runBlocking {
// WRONG usage:
// launch(NonCancellable) { ... } // launches a coroutine that cannot be cancelled
// RIGHT usage:
launch {
try { delay(500) }
finally {
withContext(NonCancellable) {
println("Safe cleanup")
}
}
}.also { delay(50); it.cancel(); it.join() }
}การล้างทรัพยากรหลายรายการ
เชื่อมการดำเนินการล้างข้อมูลหลายรายการไว้ภายในบล็อก withContext(NonCancellable) เดียว
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
try {
delay(1000)
} finally {
withContext(NonCancellable) {
delay(20); println("Step 1: flush cache")
delay(20); println("Step 2: close socket")
delay(20); println("Step 3: log audit")
}
}
}.also { delay(50); it.cancel(); it.join() }
}รูปแบบ try/catch/finally
ใช้ try-catch ร่วมกับข้อผิดพลาดทางธุรกิจ และใช้ finally สำหรับการล้างข้อมูล นี่คือรูปแบบมาตรฐานสำหรับการทำงานที่มีโครงสร้าง
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
try {
delay(100)
throw RuntimeException("business error")
} catch (e: RuntimeException) {
println("Handling: ${e.message}")
} finally {
withContext(NonCancellable) {
println("Always cleanup")
}
}
}.join()
}ลำดับการล้างข้อมูล
บล็อก Finally จะทำงานในลำดับย้อนกลับจากการซ้อนกัน บล็อก try-finally ภายนอกจะทำงานหลังบล็อกภายใน เช่นเดียวกับโค้ด Java/คอตลินทั่วไป
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
try {
try {
delay(1000)
} finally { println("Inner cleanup") }
} finally { println("Outer cleanup") }
}.also { delay(50); it.cancel(); it.join() }
}use() สำหรับทรัพยากร AutoCloseable
สำหรับทรัพยากร AutoCloseable ให้ใช้ส่วนขยาย use { } ของคอตลิน ซึ่งจะเรียก close() โดยอัตโนมัติ แม้เกิดข้อยกเว้นหรือการยกเลิก
import kotlinx.coroutines.*
class Connection : AutoCloseable {
init { println("Opened") }
override fun close() { println("Closed") }
suspend fun query(): String { delay(50); return "result" }
}
fun main() = runBlocking {
val result = Connection().use { it.query() }
println(result)
}การบันทึกเหตุผลของการยกเลิก
ดึงข้อความการยกเลิกจาก CancellationException ใน catch หรือ finally เพื่อบันทึกว่าเหตุใดโคโรทีนจึงหยุดทำงาน
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} catch (e: CancellationException) {
println("Cancelled: ${e.message}")
throw e
}
}
delay(50)
job.cancel("user navigated away")
job.join()
}การล้าง CoroutineScope ด้วย invokeOnCompletion
Job.invokeOnCompletion จะลงทะเบียนฟังก์ชันเรียกกลับที่ทำงานเมื่องานเสร็จสิ้นไม่ว่าด้วยเหตุผลใด ซึ่งเป็นทางเลือกแทน finally สำหรับการล้างข้อมูลในระดับแม่
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(1000)
}
job.invokeOnCompletion { cause ->
if (cause != null) println("Ended with: ${cause::class.simpleName}")
else println("Completed normally")
}
delay(50)
job.cancel()
job.join()
}ตรวจสอบอย่างรวดเร็ว
withContext(NonCancellable) ในบล็อก finally มีจุดประสงค์อะไร
ทบทวน
finally จะทำงานเสมอเมื่อมีการยกเลิก ให้ครอบการเรียกที่มีการระงับการทำงานภายใน finally ด้วย withContext(NonCancellable) เพื่อให้การเรียกเหล่านั้นเสร็จสิ้นแม้เกิดการยกเลิก ใช้ use { } กับทรัพยากร AutoCloseable
เรียนรู้ Kotlin ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 51
- บทเรียน
- 203
คำถามที่พบบ่อย
บทเรียน “การเก็บกวาดด้วย finally และ NonCancellable” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเก็บกวาดด้วย finally และ NonCancellable” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเก็บกวาดด้วย finally และ NonCancellable”
คืนทรัพยากรใน coroutine ที่ถูกยกเลิกด้วย finally และ withContext(NonCancellable) คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การเก็บกวาดด้วย finally และ NonCancellable” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การยกเลิกร่วมมือกัน: isActive และ ensureActive
- withTimeout และ withTimeoutOrNull
- การเก็บกวาดด้วย finally และ NonCancellable
- การส่งต่อการยกเลิกในลำดับชั้น Coroutine