好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java协程编程之Loom

Java协程编程Loom

前提:

OpenJDK给出的官网https://openjdk.java.net/projects/loom有少量Loom项目相关的信息)JDK17编译和JDK18编译等早期版本,Loom早期版本JDK18编译的版本:下载入口在:https://jdk.java.net/loom

由于该JDK版本过高,目前可以使用主流IDE导入Loom-JDK-18+9进行代码高亮和语法提醒,暂时找不到方法进行编译,暂时使用该JDK执行目录下的的javac命令脚本进行编译,使用java命令脚本运行。

1、Loom项目简单介绍

?

1

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 修饰符,隐藏在 java.lang 包中,并且 VirtualThread 是 Thread 的子类。协程的创建API位于 Thread 类中:

使用此API创建协程如下:

?

1

2

3

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 类引入了建造者模式,比较合理地解决了这个问题:

?

1

2

3

4

5

6

7

8

9

// 创建平台线程建造器,对应于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方法链展开 如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

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()方法:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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目录下的工具编译和运行,具体如下:

?

1

2

3

# 执行 - 当前目录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的资料请关注其它相关文章!

原文链接:https://HdhCmsTestcnblogs测试数据/throwable/p/15164665.html

查看更多关于Java协程编程之Loom的详细内容...

  阅读:21次