Java 协程 Quasar
线程在阻塞状态和可运行状态的切换,以及线程间的上下文切换都会造成性能的损耗。为了解决这些问题,引入协程coroutine
这一概念,就像在一个进程中允许存在多个线程,在一个线程中,也可以存在多个协程。
使用协程究竟有什么好处呢?
首先,执行效率高。线程的切换由操作系统内核执行,消耗资源较多。而协程由程序控制,在用户态执行,不需要从用户态切换到内核态,我们也可以理解为,协程是一种进程自身来调度任务的调度模式,因此协程间的切换开销远小于线程切换。
其次,节省资源。因为协程在本质上是通过分时复用了一个单线程,因此能够节省一定的资源。
虽然在Java官方的jdk中不能直接使用协程,但是,有其他的开源框架借助动态修改字节码的方式实现了协程,比如Quasar。
1 2 3 4 5 | <dependency> <groupId>co.paralleluniverse</groupId> <artifactId>quasar-core</artifactId> <version> 0.7 . 10 </version> </dependency> |
下面我们模拟一个简单的场景,假设我们有一个任务,平均执行时间为1秒,分别测试一下使用线程和协程并发执行10000次需要消耗多少时间。
先通过线程进行调用,直接使用Executors
线程池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch( 10000 ); long start = System.currentTimeMillis(); ExecutorService executor = Executors.newCachedThreadPool(); for ( int i = 0 ; i < 10000 ; i++) { executor.submit(() -> { try { TimeUnit.SECONDS.sleep( 1 ); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); }); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println( "Thread use:" + (end - start) + " ms" ); } |
下面我们再用Quasar中的协程跑一下和上面相同的流程。这里我们要使用的是Quasar中的Fiber
,它可以被翻译为协程或纤程,创建Fiber
的类型主要可分为下面两类:
1 2 | public Fiber(String name, FiberScheduler scheduler, int stackSize, SuspendableRunnable target); public Fiber(String name, FiberScheduler scheduler, int stackSize, SuspendableCallable<V> target); |
在Fiber
中可以运行无返回值的SuspendableRunnable
或有返回值的SuspendableCallable
,看这个名字也知道区别就是java中的Runnable
和Callable
的区别了。其余参数都可以省略,name
为协程的名称,scheduler
是调度器,默认使用FiberForkJoinScheduler
,stackSize
指定用于保存fiber调用栈信息的stack
大小。
在下面的代码中,使用了Fiber.sleep()
方法进行协程的休眠,和Thread.sleep()
非常类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch= new CountDownLatch( 10000 ); long start = System.currentTimeMillis(); for ( int i = 0 ; i < 10000 ; i++) { new Fiber<>( new SuspendableRunnable(){ @Override public void run() throws SuspendExecution, InterruptedException { Fiber.sleep( 1000 ); countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println( "Fiber use:" +(end-start)+ " ms" ); } |
直接运行,报了一个警告:
1 | QUASAR WARNING: Quasar Java Agent isn 't running. If you' re using another instrumentation method you can ignore this message; otherwise, please refer to the Getting Started section in the Quasar documentation. |
Quasar生效的原理是基于Java instrument
技术吗,所以这里需要给它添加一个代理Agent。找到本地maven仓库中已经下好的jar包,在VM options
中添加参数:
1 | -javaagent:C:\Users\tl19638\.m2\repository\co\paralleluniverse\quasar-core\ 0.7 . 10 \quasar-core- 0.7 . 10 .jar |
运行后时间只有使用线程池时的一半多一点,确实能大大缩短程序的效率。
文章参考:https://mp.weixin.qq.com/s/U1IlB_fv2BMAs5r74kDdNg
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2021-03-25 MySQL 8 通用表表达式 with as
2017-03-25 css 蒙层
2017-03-25 css 多行文本的溢出显示省略号(移动端)
2017-03-25 移动端利用-webkit-box水平垂直居中(旧弹性盒)
2017-03-25 去除inline-block元素间间距
2017-03-25 js定时器setInterval()与setTimeout()