ava使用的是系统级线程,也就是说,每次调用new Thread(....).run(),都会在系统层面建立一个新的线程,然鹅新建线程的开销是很大的(每个线程默认情况下会占用1MB的内存空间,当然你愿意的话可以用-Xss来调小点),更不要说线程切换带来的开销了

为了节省开销,程序员玩出了很多花样。

最常用的是线程池(线程复用,但是完全无法处理阻塞调用的问题)

以及事件驱动框架(NIO或者Netty,用少量的工作线程来服务大量的慢速IO连接,但是EventLoop中也不能有阻塞调用,耗时的逻辑必须放在额外的线程池里处理)

但是NIO的代码难写也难懂,像我这种懒惰的程序猴子,最喜欢的还是一个线程对应一个连接这种简单粗暴的编程手法。

纤程(Coroutine)是我们的救星

所谓的纤程,或者协程,可以理解为是一种轻量级的线程,它与线程的主要区别在于

a. 线程切换的过程是由系统内核完成,切换的过程中会进入到内核态。而纤程则完全工作在用户态。

b. 线程是否发生切换是由操作系统决定的(抢占式调度),工作线程本身没有决定权。而纤程的切换是需要工作纤程主动放弃CPU,这样调度器才能让另外一个纤程继续运行。

很多语言已经内置了纤程,最著名的应该就是Go了,用go关键字,就能直接创建一个纤程并在其中为所欲为,其他的Scheduler会自动帮你搞定。所以Go能相对容易的写出正确的高并发程序。

可惜的是,Java没有官方的纤程支持,好在有个叫做Quasar的库可堪一用

使用这个lib,你就能在Java程序中创建纤程了,代码大概长这个样子:

    public static void main(String[] args)
throws ExecutionException, InterruptedException, SuspendExecution {
int FiberNumber = 1_000_000;
CountDownLatch latch = new CountDownLatch(1);
AtomicInteger counter = new AtomicInteger(0); for (int i = 0; i < FiberNumber; i++) {
new Fiber(() -> {
counter.incrementAndGet();
if (counter.get() == FiberNumber) {
System.out.println("done");
}
Strand.sleep(1000000);
}).start();
}
latch.await();
}

在上面这段代码中,我们直接创建了一百万个纤程,如果是一般的Thread,不考虑OS能否负担得起,单单占用的内存就要1T起步。

但是这段程序实际占用的内存只在1G出头,也就是说每个纤程的内存占用只在1K左右。

这是如何做到的?

Quasar在编译时会对代码进行扫描,如果方法带有Suspendable注解,或者抛出SuspendExecution,或者在配置文件中被指定,Quasar会直接修改生成的字节码,在park方法的前后,插入一些字节码。

这些字节码会记录此时纤程的执行状态(相关的局部变量与操作数栈),然后通过抛出异常的方式将CPU的控制权从当前协程交回到控制器

此时控制器可以再次调度另外一个纤程运行,并通过之前插入的那些字节码恢复当前纤程的执行状态,使程序能继续正常执行。

并且,这些操作是非常轻量的,所以内存消耗极小,也不会对CPU带来太多的额外开销(据说在3%-5%)

JAVA协程 纤程 与Quasar 框架的更多相关文章

  1. Java 中的纤程库 – Quasar

    来源:鸟窝, colobu.com/2016/07/14/Java-Fiber-Quasar/ 如有好文章投稿,请点击 → 这里了解详情 最近遇到的一个问题大概是微服务架构中经常会遇到的一个问题: 服 ...

  2. 继续了解Java的纤程库 – Quasar

    前一篇文章Java中的纤程库 – Quasar中我做了简单的介绍,现在进一步介绍这个纤程库. Quasar还没有得到广泛的应用,搜寻整个github也就pinterest/quasar-thrift这 ...

  3. 纤程与Quasar

    Java使用的是系统级线程,也就是说,每次调用new Thread(....).run(),都会在系统层面建立一个新的线程,然鹅新建线程的开销是很大的(每个线程默认情况下会占用1MB的内存空间,当然你 ...

  4. 协程,纤程(Fiber),或者绿色线程(GreenThread)

    纤程(Fiber),或者绿色线程(GreenThread) 面试官:你知道协程吗? 你:订机票的那个吗,我常用. 面试官:行,你先回去吧,到时候电话联系 ........ 很尴尬,但是事实是,很大一部 ...

  5. java 协程

    协程是比线程更轻量级的程序处理单元,也可以说是运行在线程上的线程,由自己控制 1.适用于被阻塞的,且需要大量并发的场景. 2.不适用于,大量计算的多线程,遇到此种情况,更好实用线程去解决. 虽然Jav ...

  6. Java协程实践指南(一)

    一. 协程产生的背景 说起协程,大多数人的第一印象可能就是GoLang,这也是Go语言非常吸引人的地方之一,它内建的并发支持.Go语言并发体系的理论是C.A.R Hoare在1978年提出的CSP(C ...

  7. Java协程编程之Loom项目尝鲜

    前提 之前很长一段时间关注JDK协程库的开发进度,但是前一段时间比较忙很少去查看OpenJDK官网的内容.Java协程项目Loom(因为项目还在开发阶段,OpenJDK给出的官网https://ope ...

  8. 基于纤程(Fiber)实现C++异步编程库(一):原理及示例

    纤程(Fiber)和协程(coroutine)是差不多的概念,也叫做用户级线程或者轻线程之类的.Windows系统提供了一组API用户创建和使用纤程,本文中的库就是基于这组API实现的,所以无法跨平台 ...

  9. nodejs中的fiber(纤程)库详解

    fiber/纤程 在操作系统中,除了进程和线程外,还有一种较少应用的纤程(fiber,也叫协程).纤程常常拿来跟线程做对比,对于操作系统而言,它们都是较轻量级的运行态.通常认为纤程比线程更为轻量,开销 ...

随机推荐

  1. vue的组件名称问题

    如果组件名称中带有大写字母,那么会报错

  2. java web 向数据库插入中文数据乱码问题

    一.先检查下是 页面返回数据时已经乱码了,还是在插入数据库的时候乱的码. 二.页面返回乱码: 1.  Web.XML  文件配置 <!-- 配置编码过滤器 --> <filter&g ...

  3. jquery定义链接跳转的高亮显示

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 【安卓周记】笔记复习记录:No.2

    [安卓] 1. Activity横竖屏切换生命周期变化,分三种情况: 1. 没有配置android:configChanges:每次横竖屏切换都会重新走一遍生命周期 2. 配置android:conf ...

  5. YAML_05 定义一个变量创建用户,设置密码

    ansible]# vim user2.yml --- - hosts: cache   remote_user: root   vars:     user: wangwu   tasks:     ...

  6. 1.7volatile关键字

    volatile volatile关键字的主要作用是使变量在多个线程间可见 使用方法: private volatile int number=0; 图示: 两个线程t1和t2共享一份数据,int a ...

  7. Pytest权威教程11-模块及测试文件中集成doctest测试

    目录 模块及测试文件中集成doctest测试 编码 使用doctest选项 输出格式 pytest-specific 特性 返回: Pytest权威教程 模块及测试文件中集成doctest测试 编码 ...

  8. JS中的constructor 和 prototype

    object.constructor :对象的constructor 属性引用了该对象的构造函数. //例如,用Array()构造函数创建了一个数组,那么a.constructor 引用的就是Arra ...

  9. 4、vueJs基础知识04

    简单的目录结构: |-index.html |-main.js 入口文件 |-App.vue vue文件(组件),官方推荐命名法(首字母大写) |-components      组件存放的文件夹 | ...

  10. vue+element 表格formatter数据格式化并且插入html标签

    前言 vue中 element框架,其中表格组件,我既要行内数据格式化,又要插入html标签 一贯思维,二者不可兼得也 一.element 表格 数据格式化 demo <el-table-col ...