출처: https://www.boostcourse.org/mo234/lecture/154327?isDesc=false
[blocking] Task A와 B가 싱크를 맞춘다고 보면 된다. A의 작업이 완료되고 나서 B가 실행되고, B의 작업이 완료되고 나서 A가 실행된다.
[non-blocking] 아까와는 다르게 A의 작업이 완료되지 않더라도 블로킹 되지 않고 B가 실행될 수 있다. 이때 A와 B는 OS 스케줄러에 의해 시분할 되어 동시에 실행되는 것처럼 보인다. (코어가 여러 개일 경우에는 서로 다른 코어에서 A와 B가 실제로 동시에 실행된다.)
하나의 프로세스나 스레드가 CPU를 사용하고 있는 상태에서 다른 프로세스나 스레드가 CPU를 사용하도록 만들기 위해, 이전의 프로세스 상태를 보관하고 새로운 프로세스 상태를 적재하는 과정
package chap06.section1
// 1. 클래스 상속
class SimpleThread: Thread() {
override fun run(){
println("Class Thread ${currentThread()}")
}
}
// 2. 인터페이스 구현
class SimpleRunnable: Runnable {
override fun run() {
println("Interface Thread ${Thread.currentThread()}")
}
}
fun main() {
val thread = SimpleThread()
thread.start() // 메인 스레드와는 별도의 스레드 실행
val runnable = SimpleRunnable()
val thread2 = Thread(runnable)
thread2.start()
// 3. 익명객체 생성과 동시에 스레드 실행
object: Thread(){
override fun run(){
println("object Thread: ${currentThread()}")
}
}.start()
// 4. 람다식 사용
Thread {
println("Lambda Thread: ${Thread.currentThread()}")
}.start()
}
Class Thread Thread[Thread-0,5,main]
Interface Thread Thread[Thread-1,5,main]
object Thread: Thread[Thread-2,5,main]
Lambda Thread: Thread[Thread-3,5,main]
package chap06.section1
fun thread(start: Boolean = true, isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null, name: String? = null,
priority: Int = -1, block: () -> Unit): Thread {
val thread = object: Thread() {
override fun run(){
block()
}
}
if(isDaemon)
thread.isDaemon = true
if(priority > 0)
thread.priority = priority
if(name != null)
thread.name = name
if(contextClassLoader != null)
thread.contextClassLoader = contextClassLoader
if(start)
thread.start()
return thread
}
fun main() {
thread(start = true){
println("Current Thread: ${Thread.currentThread()}")
println("Priority: ${Thread.currentThread().priority}")
println("Name: ${Thread.currentThread().name}")
println("isDaemon: ${Thread.currentThread().isDaemon}")
}
}
Current Thread: Thread[Thread-0,5,main]
Priority: 5
Name: Thread-0
isDaemon: false
자주 재사용되는 스레드를 이용하기 위해서 미리 생성된 스레드풀에서 스레드를 이용할 수 있다.
ex) 8개의 스레드로 특정 백그라운드 서비스를 하도록 만드는 경우
val myService: ExecutorService = Executors.newFixedThreadPool(8)
var i = 0
while(i < items.size) { // 아주 큰 데이터를 처리할 때
val item = items[i]
myService.submit {
processItem(item) // 여기서 아주 긴 시간 동안 데이터 처리
}
}