Multi Thread
방식 사용Thread
클래스, Runnable
인터페이스 사용start
: 구성한 스레드 환경 실행(run 실행)run
: 다른 스레드 내부에서 실행될 작업 jon
: 해당 스레드의 종료 시점까지 호출한 스레드를 중지sleep
: 스레드 일시 중지// Thread
Thread(
object : Runnable{
override fun run() {
println("Thread Class")
}
}
).start()
// Thread Lambda
Thread { println("Thread Lambda") }.start()
// Thread 상속
class MyThread : Thread() {
override fun run() {
println("Thread Extends")
}
}
MyThread().start()
// 코틀린 제공 함수
thread {
println("Kotlin Library Thread")
} // default: 생성시 실행
멀티 스레드 환경에서는 stack을 제외한 자원을 서로 공유하기때문에 하나의 개체에 대해 여러 쓰레드가 접근시 문제가 발생할 수 있다.
var num = 0
for (i in 0 until 1000) {
thread {
Thread.sleep(10)
num += 1
}
}
Thread.sleep(2000)
print(num) // 1000이 안될 가능성이 높음
synchronized 함수
val lock = Any()
var num = 0
for (i in 1..1000) {
thread {
Thread.sleep(10)
synchronized(lock) {
num += 1
}
}
}
Thread.sleep(2000)
print(num) // print: 1000
synchronized 어노테이션
@Synchronized
fun syncMethod() = run { }
AtomicInteger, 원자성 자료형
val num = AtomicInteger(0)
for (i in 1..1000) {
thread {
Thread.sleep(10)
num.incrementAndGet()
}
}
Thread.sleep(5000)
print(num.get()) // print: 1000
ReentrantLock, 복잡한 설정
private val lock: ReentrantLock = ReentrantLock(true)
fun foo(){
lock.withLock {
doSomething()
}
}
하드웨어의 제한적인 사항(CPU, Memory 등)이 있기 때문에
Thread를 관리하는 Thread Pool이라는 개념을 이용한다.
FixedThreadPool
고정된 수의 스레드로 작업 처리하며 추가적인 작업은 작업 큐에서 대기
작업 흐름이 일정하고 항상 대략 같은 수준일 때 사용
val executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
CachedThreadPool
작업의 요구 사항에 따라 동적으로 리소스 활용
작업 요청이 증가하면 스레드를 생성하고, 유휴 상태로 장시간 대기하면 스레드를 제거
val executorService = Executors.newCachedThreadPool()
SingleThreadExecutor
하나의 스레드만을 사용, 작업 큐에 있는 작업을 순차적으로 처리
순차적인 작업이 필요한 경우 사용
val executorService = Executors.newSingleThreadExecutor()
Runnable
작업 완료 후 반환값이 존재하지 않으며 Exception을 발생시키지 않는다.
Callable
작업 완료 후 반환값이 존재하며 Exception을 발생
FutureTask를 통해 Callable 호출 및 Future<V>
반환
val callable = Callable<String> { TODO("Not yet implemented") }
val runnable = Runnable { TODO("Not yet implemented") }
execute(Runnable)
작업 처리 결과는 반환하지 않는다.
처리 도중 예외가 발생하면 Thread가 종료되고 해당 Thread는 Thread Pool에서 제거된다.
submit(Callable || Runnable)
작업 처리 결과를 Future 타입의 객체로 반환한다.
처리 도중 예외가 발생하면 Thread는 종료되지 않고 다음 작업을 위해 재사용
val future1: Future<String> = executeService.submit(callable)
executeService.execute(runnable)
shutdown
작업 Queue에 남아있는 작업까지 모두 마무리한 후 Thread 종료
shutdownNow
작업 Queue에 남아있는 작업 잔량에 상관없이 강제 종료
awaitTermination(long timeout, TimeUnit unit)
모든 작업 처리를 timeout 시간 안에 처리 시 true 반환, 처리하지 못하면 작업 Thread를 interrupt 시키고 false 반환한다.