ExecutorService를 사용하면 쉽고 안전하게 스레드풀을 사용할 수 있다. fun main() {
val pool: ExecutorService = Excutors.newFixdThreadPool(5)
try {
for (i in 0 <= .. <= 5) { // 1,2,3,4,5,1 순서로 출력됨.
pool.execute {
println("current-thread-name : ${Thread.currentThread().name}")
}
}
} finally {
pool.shutdown()
}
println("current-thread-name : ${Thread.currentThread().name}")
}
fun main() {
val completableFuture = CompletableFuture.supplyAsync {
Thread.sleep(2000)
sum(100, 200)
}
println("계산 시작")
val result = completableFuture.thenApplyAsync(::println)
//이 이후의 코드들이 블로킹되지 않고 계속 수행된다.
//Future.get()의 경우 블로킹되어 이후 코드들이 수행되지 않음.
println(result)
while(!completableFuture.isDone) {
Thread.sleep(500)
println("계산 결과를 집계 중입니다.")
}
}

서브젝트와 서브젝트를 관찰하는 옵저버로 이뤄져 있다.Push 방식이다. class Coffee(val name: String)
class Barista : Observable() {
private lateinit var coffeeName: String
fun orderCoffee(name: String) {
this.coffeeName = name
}
fun makeCoffee() {
setChanged()
notifyObservers(Coffee(this.coffeeName))
}
}
class Customer(val name: String) : Observer {
override fun update(o: Observable?, arg: Any?) {
val coffee = arg as Coffee
prntln("${name}이 ${coffee.name}을 받았습니다.")
}
}
fun main() {
val barista = Barista()
barista.orderCoffee("아이스 아메리카노")
val cust1 = Customer("고객1")
val cust2 = Customer("고객2")
barista.addObserver(cust1)
barista.addObserver(cust2)
barista.makeCoffee()
//모든 고객(옵저버)에게 통지가 되고 고객의 update 메서드 실행
}

Pull방식이다. data class Car(val brand:String)
class CarIterable(val cars: List<Car> = ListOf()) : Iterable<Car> {
override fun iterator(): Iterator<Car> = CarIterator(cars)
}
class CarIterator(val cars: List<Car> = ListOf(), car index : Int = 0) : Iterator<Car> {
override fun hasNext(): Boolean {
return cars.size > index
}
override fun next(): Car {
return cars[index++]
}
}
fun main() {
val carIterable = CarIterable(ListOf(Car("람보르기니"), Car("페라리")))
val iterator = carIterable.iterator()
while (iterator.hesNext()) {
println("브랜드 : ${iterator.next()}")
}
}
fetch("/api/me") { user ->
fetch("/api/${user.id}/followers") { followers ->
fetch("/api/${user.id}/likes") { likes ->
//콜백 헬
}
}
}
fetchReactive("/api/me")
.zip { user -> fetchReactive("/api/${user.id}/followers")
.zip { user -> fetchReactive("/api/${user.id}/likes")
.flatMap { follwers, likes ->
//로직 구현
}

핵심 인터페이스와 프로토콜로 구성된다. Publisher : 데이터를 생성하고 구독자에게 통지Subscriber : 데이터를 구독하고 통지받은 데이터를 처리Subscription : Publisher, Subscriber 간의 데이터를 교환하도록 연결하는 역할, 데이터의 개수를 설정하거나 구독 해지 가능Processor : Publisher, Subscriber를 모두 상속받은 인터페이스 무한하고 순차적 처리를 보장한다.매개체이며 구독자가 데이터를 요청하거나 구독을 해지하는 등 데이터 조절에 관련된 역할 데이터를 가공하는 중간 단계에서 사용onSubscribe : 구독시 최초에 한번만 호출
onNext : 구독자가 요구하는 데이터의 수만큼 호출
onError : 에러 또는 더이상 처리할 수 없는 경우
onComplete : 모든 처리가 완료된 경우

onSubscribe는 최초 구독에 대한 초기화를 담당한다. onNext는 발행자로부터 통지받을 데이터가 있는 경우 구독자가 요청하는 만큼 계속 호출된다. 이때 발행자가 통지하는 데이터의 수는 구독자가 요구하는 수와 같거나 적어야 한다. 이런 사양은 발행자가 너무 많은 데이터를 통지할 경우 문제가 발생할 수 있기 때문이다. onError를 구독자에게 통지하고 더이상 데이터를 통지하지 않는다. 구독자는 onError 시그널을 받으면 이에 대한 에러 처리를 할 수 있다. onComplete는 모든 데이터가 통지 완료되면 호출된다. 이후 어떤 시그널도 발생하면 안된다.