课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
大家在学习java编程开发语言的时候大部分学习的都是java进程或者java线程等方面的技术知识,对于java协程相信了解不多吧,而今天我们就通过案例分析来了加一下,java编程开发协程的概念与应用。
这东西其实有很多名词,比如有的人喜欢称为纤程(Fiber),或者绿色线程(GreenThread)。其实直观的解释可以定义为线程的线程。有点拗口,但本质上就是这样。
我们先回忆一下线程的定义,操作系统产生一个进程,进程再产生若干个线程并行的处理逻辑,线程的切换由操作系统负责调度。传统语言C++Java等线程其实与操作系统线程是1:1的关系,每个线程都有自己的Stack,Java在64位系统默认Stack大小是1024KB,所以指望一个进程开启上万个线程是不现实的。但是实际上我们也不会这么干,因为起这么多线程并不能充分的利用CPU,大部分线程处于等待状态,CPU也没有这么核让线程使用。所以一般线程数目都是CPU的核数。
传统的J2EE系统都是基于每个请求占用一个线程去完成完整的业务逻辑(包括事务)。所以系统的吞吐能力取决于每个线程的操作耗时。如果遇到很耗时的I/O行为,则整个系统的吞吐立刻下降,比如JDBC是同步阻塞的,这也是为什么很多人都说数据库是瓶颈的原因。这里的耗时其实是让CPU一直在等待I/O返回,说白了线程根本没有利用CPU去做运算,而是处于空转状态。暴殄天物啊。另外过多的线程,也会带来更多的ContextSwitch开销。
Java的JDK里有封装很好的ThreadPool,可以用来管理大量的线程生命周期,但是本质上还是不能很好的解决线程数量的问题,以及线程空转占用CPU资源的问题。
先阶段行业里的比较流行的解决方案之一就是单线程加上异步回调。其代表派是node.js以及Java里的新秀Vert.x。他们的核心思想是一样的,遇到需要进行I/O操作的地方,就直接让出CPU资源,然后注册一个回调函数,其他逻辑则继续往下走,I/O结束后带着结果向事件队列里插入执行结果,然后由事件调度器调度回调函数,传入结果。这时候执行的地方可能就不是你原来的代码区块了,具体表现在代码层面上,你会发现你的局部变量全部丢失,毕竟相关的栈已经被覆盖了,所以为了保存之前的栈上数据,你要么选择带着一起放入回调函数里,要么就不停的嵌套,从而引起反人类的Callbackhell。
因此相关的Promise,CompletableFuture等技术都是为解决相关的问题而产生的。但是本质上还是不能解决业务逻辑的割裂。
说了这么多,终于可以提一下协程了,协程的本质上其实还是和上面的方法一样,只不过他的核心点在于调度那块由他来负责解决,遇到阻塞操作,立刻yield掉,并且记录当前栈上的数据,阻塞完后立刻再找一个线程恢复栈并把阻塞的结果放到这个线程上去跑,这样看上去好像跟写同步代码没有任何差别,这整个流程可以称为coroutine,而跑在由coroutine负责调度的线程称为Fiber。比如Golang里的go关键字其实就是负责开启一个Fiber,让func逻辑跑在上面。而这一切都是发生的用户态上,没有发生在内核态上,也就是说没有ContextSwitch上的开销。
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请加danei0707学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。