在编程语言的这个圈子里,各种语言之间的对比似乎就一直就没有停过,像什么古早时期的"PHP是世界上最好的语言"就不提了,最近我在摸鱼的时候,看到不少文章都在说"Golang性能吊打Java"。作为一个写了好几年java的javaer,这我怎么能忍?于是在网上看了一些对比golang和java的文章,其中戳中java痛点、也是golang被吹上天的一条,就是对多线程并发的支持了。先看一段描述:
Go从语言层面原生支持并发,并且使用简单,Go语言中的并发基于轻量级线程
Goroutine
,创建成本很低,单个Go应用也可以充分利用CPU多核,编写高并发服务端软件简单,执行性能好,很多情况下完全不需要考虑锁机制以及由此带来的各种问题。
看到这,我的心瞬间凉了大半截,真的是字字扎心。虽然说java里的JUC
包已经帮我们封装好了很多并发工具,但实际高并发的环境中我们还要考虑到各种锁的使用,以及服务器性能瓶颈、限流熔断等非常多方面的问题。
再说回go,前面提到的这个goroutine
究竟是什么东西?其实,轻量级线程goroutine
也可以被称为协程,得益于go中的调度器以及GMP模型,go程序会智能地将goroutine
中的任务合理地分配给每个 CPU。
好了,其实上面说的这一大段我也不懂,都是向写go的哥们儿请教来的,总之就是go的并发性能非常优秀就是了。不过这都不是我们要说的重点,今天我们要讨论的是如何在Java中使用协程。
我们知道,线程在阻塞状态和可运行状态的切换,以及线程间的上下文切换都会造成性能的损耗。为了解决这些问题,引入协程coroutine
这一概念,就像在一个进程中允许存在多个线程,在一个线程中,也可以存在多个协程。
那么,使用协程究竟有什么好处呢?
首先,执行效率高。线程的切换由操作系统内核执行,消耗资源较多。而协程由程序控制,在用户态执行,不需要从用户态切换到内核态,我们也可以理解为,协程是一种进程自身来调度任务的调度模式,因此协程间的切换开销远小于线程切换。
其次,节省资源。因为协程在本质上是通过分时复用了一个单线程,因此能够节省一定的资源。
类似于线程的五种状态切换,协程间也存在状态的切换,下面这张图展示了协程调度器内部任务的流转。
综合上面这些角度来看,和原生支持协程的go比起来,java在多线程并发上还真的是不堪一击。但是,虽然在Java官方的jdk中不能直接使用协程,但是,有其他的开源框架借助动态修改字节码的方式实现了协程,就比如我们接下来要学习的Quasar。
Quasar是一个开源的Java协程框架,通过利用