Java多线程基础:虚拟线程与平台线程解析

这篇具有很好参考价值的文章主要介绍了Java多线程基础:虚拟线程与平台线程解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在这篇文章中,主要总结一些关于线程的概念,以及更近期的名为虚拟线程的特性。将了解平台线程和虚拟线程在性质上的区别,以及它们如何促进应用程序性能的改进
Java多线程基础:虚拟线程与平台线程解析,java,开发语言

经典线程背景:

让我们以调用外部API或某些数据库交互的场景为例,看看线程执行的生命周期。

  1. 线程被创建并准备在内存中提供服务。
  2. 一旦请求到达,它被映射到其中一个线程,然后通过调用外部API或执行某些数据库查询来提供服务。
  3. 线程等待,直到它从服务或数据库获取到响应。
  4. 一旦收到响应,它执行后响应的活动并返回到线程池。

Java多线程基础:虚拟线程与平台线程解析,java,开发语言
观察上述生命周期中的第3步,即线程只是等待且什么都不做。这是一个主要的缺点,通过仅等待而未充分利用系统资源,大多数线程在其生命周期中只是等待响应而无所作为。

在Java 19或更高版本之前,创建线程或现有线程的标准方式被称为本地线程或平台线程。在这种架构风格中,平台线程与操作系统线程之间存在一对一的映射。这意味着操作系统线程被低效使用,因为它只是等待活动完成而无所作为,从而使它们变得沉重且昂贵。

虚拟线程:

Java中的虚拟线程代表了Java处理并发和多线程的重要演变。作为Oracle的项目Loom的一部分引入,该项目是Oracle解决编写、维护和观察高吞吐并发应用程序所面临挑战的倡议。虚拟线程被设计为轻量级,并使并发对开发人员更加容易。

虚拟线程是由Java虚拟机(JVM)管理的轻量级线程,而不是由操作系统管理。与平台线程不同,虚拟线程创建和销毁成本较低。它们映射到较少的平台线程,使Java应用程序能够以更低的资源占用同时处理数千甚至数百万个任务。

Java多线程基础:虚拟线程与平台线程解析,java,开发语言

虚拟线程在平台线程上的有用性

虚拟线程相对于平台线程的优点是多方面的。首先,它们能够更有效地利用系统资源。由于虚拟线程轻量级,与平台线程相比,它们消耗更少的内存和CPU资源。这种效率允许更高程度的并发,使得能够在单个JVM上运行大量并发任务。

其次,虚拟线程简化了Java中的并发编程。它们允许开发人员以直观、命令式的风格编写代码,类似于编写同步代码的方式,而不必处理异步编程模型的复杂性。这种简单性降低了常见的与并发相关的错误的可能性,如死锁和竞争条件。

此外,虚拟线程促进了更好的CPU利用率。在传统的线程模型中,大量的CPU时间可能会在管理和在许多线程之间进行上下文切换方面浪费。虚拟线程减少了与上下文切换相关的开销,允许更有效地执行并发任务。

实际应用:

如果我们需要创建经典的平台线程来完成任务,我们可以按照以下步骤操作。创建一个名为PlatformThreadDemo.java的文件,并将内容复制如下。

package org.vaslabs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PlatformThreadDemo {
    private static final Logger logger = LoggerFactory.getLogger(PlatformThreadDemo.class);

    public static void main(String[] args) {
        attendMeeting().start();
        completeLunch().start();
    }

    private static Thread attendMeeting(){
        var message = "Platform Thread [Attend Meeting]";
        return new Thread(() -> {
            logger.info(STR."{} | \{message}", Thread.currentThread());
        });
    }

    private static Thread completeLunch(){
        var message = "Platform Thread [Complete Lunch]";
        return new Thread(() -> {
            logger.info(STR."{} | \{message}", Thread.currentThread());
        });
    }

    // using builder pattern to create platform threads
    private static void attendMeeting1(){
        var message = "Platform Thread [Attend Meeting]";
        Thread.ofPlatform().start(() -> {
            logger.info(STR."{} | \{message}", Thread.currentThread());
        });
    }

    private static void completeLunch1(){
        var message = "Platform Thread [Complete Lunch]";
        Thread.ofPlatform().start(() -> {
            logger.info(STR."{} | \{message}", Thread.currentThread());
        });
    }
}

上述示例展示了两种创建平台线程的方法:

  1. 使用Thread构造函数并将可运行的lambda传递给它。
  2. 使用Thread的Platform()构建方法。
    让我们通过创建一些并发的虚拟线程来看更复杂的编码。创建一个名为DailyRoutineWorkflow.java的文件,并将下面的代码复制到其中。
package org.vaslabs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class DailyRoutineWorkflow {
    static final Logger logger = LoggerFactory.getLogger(DailyRoutineWorkflow.class);

    static void log(String message) {
        logger.info(STR."{} | \{message}", Thread.currentThread());
    }


    private static void sleep(Long duration) throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(duration);
    }

    private static Thread virtualThread(String name, Runnable runnable) {
        return Thread.ofVirtual().name(name).start(runnable);
    }

    static Thread attendMorningStatusMeeting() {
        return virtualThread(
                "Morning Status Meeting",
                () -> {
                    log("I'm going to attend morning status meeting");
                    try {
                        sleep(1000L);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log("I'm done with morning status meeting");
                });
    }

    static Thread workOnTasksAssigned() {
        return virtualThread(
                "Work on the actual Tasks",
                () -> {
                    log("I'm starting my actual work on tasks");
                    try {
                        sleep(1000L);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log("I'm done with actual work on tasks");
                });
    }

    static Thread attendEveningStatusMeeting() {
        return virtualThread(
                "Evening Status Meeting",
                () -> {
                    log("I'm going to attend evening status meeting");
                    try {
                        sleep(1000L);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log("I'm done with evening status meeting");
                });
    }

    static void concurrentRoutineExecutor() throws InterruptedException {
        var morningMeeting = attendMorningStatusMeeting();
        var actualWork = workOnTasksAssigned();
        var eveningMeeting = attendEveningStatusMeeting();
        morningMeeting.join();
        actualWork.join();
        eveningMeeting.join();
    }
}

上述代码展示了使用工厂方法创建虚拟线程。除了工厂方法之外,我们还可以使用专为虚拟线程定制的java.util.concurrent.ExecutorService来实现虚拟线程,称为java.util.concurrent.ThreadPerTaskExecutor。您可以使用ExecutorService获得与上述相同的功能,如下所示。

package org.vaslabs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DailyRoutineWorkflowUsingExecutors {
    static final Logger logger = LoggerFactory.getLogger(DailyRoutineWorkflowUsingExecutors.class);

    static void log(String message) {
        logger.info(STR."{} | \{message}", Thread.currentThread());
    }


    private static void sleep(Long duration) throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(duration);
    }

    public static void executeJobRoute() throws ExecutionException, InterruptedException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            var morningMeeting = executor.submit(() -> {
                log("I'm going to attend morning status meeting");
                try {
                    sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log("I'm done with morning status meeting");
            });

            var actualWork = executor.submit(() -> {
                log("I'm starting my actual work on tasks");
                try {
                    sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log("I'm done with actual work on tasks");
            });

            var eveningMeeting = executor.submit(() -> {
                log("I'm going to attend evening status meeting");
                try {
                    sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log("I'm done with evening status meeting");
            });

            morningMeeting.get();
            actualWork.get();
            eveningMeeting.get();
        }
    }
}

深入了解输出

如果您运行上述代码,无论是使用工厂方法还是ExecutorServices,您将看到类似于以下的输出。
Java多线程基础:虚拟线程与平台线程解析,java,开发语言
仔细观察信息日志,您将看到“|”(管道符号)两侧的两个部分,第一部分解释了有关虚拟线程的信息,如VirtualThread[#26]/runnable@ForkJoinPool-1-worker-3。这告诉我们VirtualThread[#26]映射到平台线程runnable@ForkJoinPool-1-worker-3,而另一部分是日志的信息部分。

ThreadLocals和虚拟线程:

在Java中,ThreadLocal是一种机制,允许变量基于每个线程进行存储。访问ThreadLocal变量的每个线程都会获得其自己独立初始化的变量副本,可以在不影响其他线程中相同变量的情况下进行访问和修改。这在您想要保持特定于线程的状态(例如用户会话或数据库连接)的情景中特别有用。

然而,当与作为Loom项目的一部分引入的虚拟线程一起使用时,ThreadLocal的行为发生了显著变化。虚拟线程是由Java虚拟机(JVM)管理的轻量级线程,设计用于大量调度,而不同于与操作系统的线程管理相关联的传统平台线程。

由于可以创建数百万个虚拟线程,使用ThreadLocal可能导致内存泄漏。

package org.vaslabs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class ThreadLocalDemo {
    private static ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();

    static final Logger logger = LoggerFactory.getLogger(DailyRoutineWorkflow.class);

    static void log(String message) {
        logger.info(STR."{} | \{message}", Thread.currentThread());
    }

    private static void sleep(Long duration) throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(duration);
    }

    public static void virtualThreadContext() throws InterruptedException {
        var virtualThread1 = Thread.ofVirtual().name("thread-1").start(() -> {
            stringThreadLocal.set("thread-1");
            try {
                sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log(STR."thread name is \{stringThreadLocal.get()}");
        });
        var virtualThread2 = Thread.ofVirtual().name("thread-2").start(() -> {
            stringThreadLocal.set("thread-2");
            try {
                sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log(STR."thread name is \{stringThreadLocal.get()}");
        });
        virtualThread1.join();
        virtualThread2.join();
    }
}

总结:

虚拟线程成为一个颠覆性的变革者,提供了轻量级、高效的并发性,与平台线程资源密集型的特性形成鲜明对比。它们通过在最小资源开销下使大量并发任务成为可能,从而改变了Java处理多线程的方式,简化了编程模型并增强了应用程序的可扩展性。

然而,在这个新背景下对ThreadLocal的使用的复杂性突显了需要谨慎考虑的必要性。虽然ThreadLocal在传统线程中保持特定于线程的数据方面仍然是一个强大的工具,但在虚拟线程中,它的应用变得更加复杂,需要替代策略来进行状态和上下文管理。这些概念共同标志着Java并发范式的重大转变,为开发人员构建更具响应性、可扩展性和高效性的应用程序打开了新的大门。文章来源地址https://www.toymoban.com/news/detail-797407.html

到了这里,关于Java多线程基础:虚拟线程与平台线程解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java21虚拟线程实践

      就在前几天,java21正式版发布了,作为继java17之后的又一个长期支持版本 (LTS),为我们带来了很多新的特性,其中我最感兴趣的就是虚拟线程(virtual thread),相信大家对虚拟线程也很好奇。趁着空闲时间安装了jdk21来体验一把,顺便把我查到的关于java21虚拟线程相关的资料

    2024年02月08日
    浏览(45)
  • 【Java系列】深入解析Java多线程

    你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色 :重要标题 红色 :用来标记结论 绿色 :用来标记一级重要 蓝色 :用来标记二级重要 希望这篇文章能让你不仅有一定的收获,而且可以愉快的学习,如果有什么建议,都可以留言和我交流 思考一下

    2024年02月03日
    浏览(40)
  • 【Java 】从源码全面解析Java 线程池

    线程池技术在互联网技术使用如此广泛,几乎所有的后端技术面试官都要在线程池技术的使用和原理方面对小伙伴们进行 360° 的刁难。 作为一个在互联网公司面一次拿一次 Offer 的面霸,打败了无数竞争对手,每次都只能看到无数落寞的身影失望的离开,略感愧疚(请允许我

    2024年02月03日
    浏览(47)
  • Java 21 虚拟线程:使用指南(一)

    虚拟线程是由 Java 21 版本中实现的一种轻量级线程。它由 JVM 进行创建以及管理。虚拟线程和传统线程(我们称之为平台线程)之间的主要区别在于,我们可以轻松地在一个 Java 程序中运行大量、甚至数百万个虚拟线程。 由于虚拟线程的数量众多,也就赋予了 Java 程序强大的

    2024年02月04日
    浏览(45)
  • Java 21新特性-虚拟线程 审核中

    本文翻译自国外论坛 medium,原文地址:https://medium.com/@benweidig/looking-at-java-21-virtual-threads-0ddda4ac1be1 Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。 正如我的许多其他文章一样,在推出

    2024年02月08日
    浏览(57)
  • 「Java」《深入解析Java多线程编程利器:CompletableFuture》

    多线程编程是指在一个程序中同时执行多个线程来提高系统的并发性和响应性。在现代计算机系统中,多线程编程已经成为开发者日常工作的一部分。以下是对多线程编程需求和挑战的介绍: 需求: 提高系统的性能:通过同时执行多个线程,可以利用多核处理器的优势,实

    2024年02月11日
    浏览(50)
  • Go有协程,Java有虚拟线程,聊一聊Java Virtual Threads

    文章首发地址 Java 19 中引入了 Virtual Threads,也称为 Virtualized Threads,是 Project Loom 的核心特性之一。Virtual Threads 是一种全新的轻量级线程实现方式,它可以在 Java 应用程序中实现高效的协程编程模型。 在传统的 Java 线程模型中,每个线程都会对应一个操作系统线程,这样会带

    2024年02月16日
    浏览(55)
  • Java 新技术:虚拟线程使用指南(二)

    虚拟线程是在 Java 21 版本中实现的一种轻量级线程。它由 JVM 进行创建以及管理。虚拟线程和传统线程(我们称之为平台线程)之间的主要区别在于,我们可以轻松地在一个 Java 程序中运行大量、甚至数百万个虚拟线程。 由于虚拟线程的数量众多,也就赋予了 Java 程序强大的

    2024年02月03日
    浏览(40)
  • Java 21 新特性:虚拟线程(Virtual Threads)

    在Java 21中,引入了虚拟线程(Virtual Threads)来简化和增强并发性,这使得在Java中编程并发程序更容易、更高效。 虚拟线程,也称为“用户模式线程(user-mode threads)”或“纤程(fibers)”。该功能旨在简化并发编程并提供更好的可扩展性。虚拟线程是轻量级的,这意味着它

    2024年02月08日
    浏览(40)
  • Java 21 正式 GA,虚拟线程真的来了

    UTC 时间 2023 年 9 月 19 日,期盼已久的 Java 21 终于发布正式版! 本文一起来看看其中最受 Java 开发者关注的一项新特性:Loom 项目的两个新特性之一的 ”虚拟线程(Virtual Thread)“(另外一个新特性是 ”结构化并发(Structured Concurrency)“,当前是预览状态),它被称之为 J

    2024年02月08日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包