当前位置:Java -> Quarkus 3: Java 微服务的未来,虚拟线程及更多

Quarkus 3: Java 微服务的未来,虚拟线程及更多

在过去的四年里,开发人员已经利用 Quarkus 的力量,体验了其在将 Java 微服务从本地开发到云部署中的变革能力。当我们站在新时代的边缘时,Quarkus 3 以更加增强的功能为诱因,提升了开发体验、性能、可扩展性和无缝云集成。

在这段引人入胜的旅程中,让我们深入了解 Quarkus 3 与虚拟线程 (Project Loom) 的整合。您将了解到 Quarkus 如何使您可以简化异步并发应用程序的创建,利用虚拟线程实现卓越的可扩展性,同时确保高效的内存使用和最佳性能。

Java 线程的发展历程

如果您多年来一直在实现 Java 应用程序,可能对各种类型的 Java 线程 有一些经验。让我快速提醒您 Java 线程在过去几十年中是如何发展的。自 Java 1.0 引入以来,Java 线程经历了重大的进展。最初关注的是建立基本的并发机制,包括线程管理、线程优先级、线程同步和线程通信。随着 Java 的成熟,它引入了原子类、并发集合、ExecutorService 框架以及 LockCondition 接口,提供了更复杂和更高效的并发工具。

Java 8 标志着一个转折点,引入了函数式接口、lambda 表达式和 CompletableFuture API,使异步编程更加简洁和表达力十足。此外,Reactive Streams API 标准化了异步流处理,Project Loom 引入了虚拟线程,提供了轻量级线程和改进的并发支持。

Java 19 进一步增强了结构化并发工具,比如 FlowWorkStealing,提供了更加结构化和可组合的并发模式。这些进步极大地加强了 Java 的并发能力,使开发可扩展且高性能的并发应用程序更加容易。Java 线程不断演进,持续进行研究和开发以改善并发编程中的性能、可扩展性和开发人员生产力。

虚拟线程 在 Java 21 中已经普遍可用 (GA),这是一项革命性的并发功能,解决了传统操作系统 (OS) 线程的局限性。传统操作系统线程重量级且可扩展性受限,管理复杂,对于开发可扩展且高性能的并发应用程序提出了挑战。

虚拟线程还提供了几个优点,例如作为一种轻量级和高效的替代方案,消耗更少的内存,降低了上下文切换的开销,并支持并发任务。它们简化了线程管理,提高了性能,并增强了可扩展性,为新的并发范式铺平了道路,实现了更有效的无服务器计算和微服务架构。虚拟线程代表了 Java 并发的重大进步,有望塑造并发编程的未来。

使用虚拟线程入门

通常情况下,在 JDK 21 中,您需要使用 Thread.Builder 直接在您的 Java 项目中创建虚拟线程。例如,以下代码片段展示了开发人员如何创建一个新的虚拟线程,并从虚拟线程向控制台打印消息。Thread.ofVirtual() 方法创建一个新的虚拟线程构建器,name() 方法将虚拟线程的名称设置为 "virtual-thread"。然后,start() 方法启动虚拟线程并执行提供的 Runnable lambda 表达式,向控制台打印消息。最后,join() 方法在继续执行之前等待虚拟线程完成。主线程中的 System.out.println() 语句在虚拟线程执行完成后向控制台打印消息。

public class MyVirtualThread {

    public static void main(String[] args) throws InterruptedException {

        // Create a new virtual thread using Thread.Builder
        Thread thread = Thread
                .ofVirtual()
                .name("my-vt")
                .start(() -> {
                    System.out.println("Hello from virtual thread!");
                });

        // Wait for the virtual thread to finish executing
        thread.join();
        System.out.println("Main thread completed.");

    }

}


另外,您还可以在 JDK 21 的 Java 项目中实现 ThreadFactory 接口来启动一个新的虚拟线程。以下代码片段展示了开发人员如何定义一个实现 ThreadFactory 接口的 VirtualThreadFactory 类。这个类的 newThread() 方法使用 Thread.ofVirtual() 方法创建一个新的虚拟线程。Builder 对象的 name() 方法用于设置线程的名称,factory() 方法用于设置 ThreadFactory 对象。

// Implement a ThreadFactory to start a new virtual thread
public class VirtualThreadFactory implements ThreadFactory {

    private final String namePrefix;

    public VirtualThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }

    @Override
    public Thread newThread(Runnable r) {

        return Thread.ofVirtual()
                .name(namePrefix + "-" + r.hashCode())
                .factory(this)
                .build();
    }

}


当您尝试在虚拟线程上运行实际的方法或类时可能会觉得会变得更加复杂。幸运的是,Quarkus 使您能够跳过学习曲线,快速、高效地在虚拟线程上执行现有的阻塞服务。让我们来深入了解一下。

Quarkus 实现虚拟线程的方式

您只需牢记两件事,就可以在虚拟线程上运行应用程序。

  • 实现基于 JDK 21 的阻塞服务而不是反应式(或非阻塞)服务。
  • 在您希望的方法或类上方使用 @RunOnVirtualThread 注解。

下面是 Quarkus 允许您在虚拟线程上运行 process() 方法的代码片段。

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @RunOnVirtualThread
    public String hello() {
    
        Log.info(Thread.currentThread());
        return "Quarkus 3: The Future of Java Microservices with Virtual Threads and Beyond";
    
    }

}


您可以启动 Quarkus Dev mode (Live coding) 来验证上述示例应用程序。然后,使用 curl 命令调用 REST 端点。

$ curl http://localhost:8080/hello


输出应该如下所示。

Quarkus 3: The Future of Java Microservices with Virtual Threads and Beyond


当您查看终端时,您会发现 Quarkus dev mode 正在运行。您可以看到创建了一个虚拟线程来运行此应用程序。

(quarkus-virtual-thread-0) VirtualThread[#123,quarkus-virtual-thread-0]/runnable@ForkJoinPool-1-worker-1


尝试几次调用端点,终端中的日志应该如下所示。

您已经了解了Quarkus如何为Java开发人员整合虚拟线程以运行阻塞应用程序,并通过单个@RunOnVirtualThread注解。您应该意识到这个注解并非适用于所有用例的灵丹妙药。在接下来的文章中,我将介绍针对响应式应用程序的潜在问题、限制和性能测试结果。

推荐阅读: 百度面经(28)

本文链接: Quarkus 3: Java 微服务的未来,虚拟线程及更多