驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
CompletableFuture总的get和thenAccept的区别
/    

CompletableFuture总的get和thenAccept的区别

开篇

Java8引入的CompletableFuture是一个非常非常好用的类库,可以方便的通过它进行多个异步任务的各类花式组合。

关于这个部分,很多博客和文章都有讲到,这篇短文,主要是分别一点:getthenAccept的区别。

代码

案例1

class CompleteFutureTest {

    @Test
    fun test1() {
        
       val completableFuture = CompletableFuture<String>()

       val t1=thread(name = "t1") {
            completableFuture.get()
            println("${Thread.currentThread().name} 中被触发...")
        }

        thread(name = "t2") {
            TimeUnit.SECONDS.sleep(3)
            val result = completableFuture.complete("123")
            println("${Thread.currentThread().name} 中被赋值...")
        }

        TimeUnit.SECONDS.sleep(4)
        println(t1.isAlive)
    }
}

此时结果如下:

t2 中被赋值...
t1 中被触发...
false

因为get是在t1中阻塞,所以触发的环境也是t1

案例2

    @Test
    fun test1() {

        val completableFuture = CompletableFuture<String>()

       val t1=thread(name = "t1") {
            val result = completableFuture.thenAccept {
                println("${Thread.currentThread().name} 中被触发...")
            }
            println("${Thread.currentThread().name} 中结束...")

        }

        thread(name = "t2") {
            TimeUnit.SECONDS.sleep(2)
            val result = completableFuture.complete("123")
            println("${Thread.currentThread().name} 中被赋值...")
        }

        TimeUnit.SECONDS.sleep(3)
        println(t1.isAlive)
    }

此时结果如下:

t1 中结束...
t2 中被触发...
t2 中被赋值...
false

从上述结果我们可以发现completableFuture.thenAccept的如下几个细节:

  • 其不会阻塞线程执行
  • 回调发生在赋值的线程中,就是说其赋值的线程在哪里,触发的线程就在哪里。

总结

案例2和案例1给我们带来的启示如下:

  • thenAccept不会有线程的上下文切换。
  • get会在主线程中阻塞。
  • 当资源可以不受线程执行影响的时候,建议用thenAccept,比如netty中获取到结果后,通过channel发送发送消息,用thenAccept应该比get更优!
不积跬步,无以至千里。不积小流,无以成江海。