Java协程编程之Loom

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java协程编程之Loom
⽬录
Java协程编程Loom
1、Loom项⽬简单介绍
2、Virtual Thread使⽤
Java协程编程Loom
前提:
由于该JDK版本过⾼,⽬前可以使⽤主流IDE导⼊Loom-JDK-18+9进⾏代码⾼亮和语法提醒,暂时找不到⽅法进⾏编译,暂时使⽤该JDK执⾏⽬录下的的javac命令脚本进⾏编译,使⽤java命令脚本运⾏。

1、Loom项⽬简单介绍
Loom - Fibers, Continuations and Tail-Calls for the JVM
Loom项⽬的标题已经凸显了引⼊的三⼤新特性:
Fibers:⼏年前看过当时的Loom项⽬的测试代码就是使⽤Fiber这个API(现在这个API已经被移除),意为轻量级线程,即协程,⼜称为轻量级⽤户线程,很神奇的是在⽬前的JDK中实际上称为Virtual Thread(虚拟线程)
Continuations:直译为"连续",实现上有点像闭包,参考不少资料,尚未准确理解其具体含义,感觉可以"粗暴"解读为"程序接下来要执⾏什么"或者"下⼀个要执⾏的代码块"
Tail-Calls:尾调⽤VM级别⽀持
三个新特性不详细展开,⽬前只是EA版本,还存在修改的可能性,所以也没必要详细展开。

2、Virtual Thread使⽤
当前版本Loom项⽬中协程使⽤并没有引⼊⼀个新的公开的虚拟线程VirtualThread类,虽然真的存在VirtualThread,但这个类使⽤default修饰符,隐藏在ng包中,并且VirtualThread是Thread的⼦类。

协程的创建API位于Thread类中:
使⽤此API创建协程如下:
public static void main(String[] args) {
Thread fiber = Thread.startVirtualThread(() -> System.out.println("Hello Fiber"));
}
从当前的源码可知:
VirtualThread会通过Thread.currentThread()获取⽗线程的调度器,如果在main⽅法运⾏,那么上⾯代码中的协程实例的⽗线程就是main线程
默认的调度器为系统创建的ForkJoinPool实例(VirtualThread.DEFAULT_SCHEDULER),输⼊的Runnable实例会被封装
为RunContinuation,最终由调度器执⾏
对于timed unpark(正在阻塞,等待唤醒)的协程,使⽤系统创建的ScheduledExecutorService实例进⾏唤醒
这个静态⼯⼚⽅法创建完协程马上运⾏,返回的是协程实例
如果按照上⾯的Thread.startVirtualThread()⽅法去创建协程,显然⽆法定义协程的名称等属性。

Loom项⽬为Thread类引⼊了建造者模式,⽐较合理地解决了这个问题:
// 创建平台线程建造器,对应于Thread实例
public static Builder.OfPlatform ofPlatform() {
return new ThreadBuilders.PlatformThreadBuilder();
}
// 创建虚拟线程建造器,对应于VirtualThread
public static Builder.OfVirtual ofVirtual() {
return new ThreadBuilders.VirtualThreadBuilder();
}
简单说就是:
ofPlatform()⽅法⽤于构建Thread实例,这⾥的Platform Thread(平台线程)其实就是JDK1.0引⼊的线程实例,普通的⽤户线程
ofVirtual()⽅法⽤于构建VirtualThread实例,也就是构建协程实例
这两个建造器实例的所有Setter⽅法链展开如下:
public static void main(String[] args) {
Thread.Builder.OfPlatform platformThreadBuilder = Thread.ofPlatform()
// 是否守护线程
.daemon(true)
// 线程组
.group(Thread.currentThread().getThreadGroup())
// 线程名称
.name("thread-1")
// 线程名称前缀 + 起始⾃增数字 => prefix + start,下⼀个创建的线程名称就是prefix + (start + 1)
// start > 0的情况下会覆盖name属性配置
.name("thread-", 1L)
// 是否启⽤ThreadLocal
.allowSetThreadLocals(false)
// 是否启⽤InheritableThreadLocal
.inheritInheritableThreadLocals(false)
// 设置优先级
.priority(100)
// 设置线程栈深度
.stackSize(10)
// 设置未捕获异常处理器
.uncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
}
});
// thread-1
Thread firstThread = platformThreadBuilder.unstarted(() -> System.out.println("Hello Platform Thread First"));
// thread-2
Thread secondThread = platformThreadBuilder.unstarted(() -> System.out.println("Hello Platform Thread Second"));
Thread.Builder.OfVirtual virtualThreadBuilder = Thread.ofVirtual()
// 协程名称
.name("fiber-1")
// 协程名称前缀 + 起始⾃增数字 => prefix + start,下⼀个创建的协程名称就是prefix + (start + 1)
// start > 0的情况下会覆盖name属性配置
.name("fiber-", 1L)
// 是否启⽤ThreadLocal
.allowSetThreadLocals(false)
// 是否启⽤InheritableThreadLocal
.inheritInheritableThreadLocals(false)
// 设置调度器,Executor实例,也就是调度器是⼀个线程池,设置为NULL会使⽤VirtualThread.DEFAULT_SCHEDULER
.scheduler(null)
// 设置未捕获异常处理器
.uncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
}
});
// fiber-1
Thread firstFiber = virtualThreadBuilder.unstarted(() -> System.out.println("Hello Platform Virtual First"));
// fiber-2
Thread secondFiber = virtualThreadBuilder.unstarted(() -> System.out.println("Hello Platform Virtual Second"));
}
这⾥可以发现⼀点,就是建造器是可以复⽤的。

如果想⽤建造器创建同⼀批参数设置相同的线程或者协程,可以设置name(String prefix, long start)⽅法,定义线程或者协程的名称前缀和⼀个⼤于等于0的数字,反复调⽤Builder#unstarted(Runnable task)⽅法就能批
量创建线程或者协程,名称就设置为prefix + start、prefix + (start + 1)、prefix + (start + 2)以此类推。

协程创建基本就是这么简单,运⾏的话直接调⽤start()⽅法:
public class FiberSample2 {
public static void main(String[] args) throws Exception {
Thread.ofVirtual()
.name("fiber-1")
.allowSetThreadLocals(false)
.inheritInheritableThreadLocals(false)
.unstarted(() -> {
Thread fiber = Thread.currentThread();
System.out.printf("[%s,daemon:%s,virtual:%s] - Hello World\n", fiber.getName(),
fiber.isDaemon(), fiber.isVirtual());
}).start();
// 主线程休眠
Thread.sleep(Long.MAX_VALUE);
}
}
⽬前⽆法在主流IDE编译上⾯的类,所以只能使⽤该JDK⽬录下的⼯具编译和运⾏,具体如下:
# 执⾏ - 当前⽬录I:\J-Projects\framework-source-code\fiber-sample\src\main\java
(1)编译:I:\Environment\Java\jdk-18-loom\bin\javac.exe I:\J-Projects\framework-source-code\fiber-sample\src\main\java\cn\throwx\fiber\sample\FiberSample2.java
(2)执⾏main⽅法:I:\Environment\Java\jdk-18-loom\bin\java.exe cn.throwx.fiber.sample.FiberSample2
这⾥也看出了⼀点,所有的协程实例的daemon标识默认为true且不能修改
以上就是Java协程编程之Loom的详细内容,更多关于Java编程Loom的资料请关注其它相关⽂章!。

相关文档
最新文档