0

0

掌握 Java 并发性:CompletableFuture、Fork/Join 及其他

花韻仙語

花韻仙語

发布时间:2024-12-13 20:21:01

|

926人浏览过

|

来源于dev.to

转载

掌握 java 并发性:completablefuture、fork/join 及其他

作为一名拥有多年经验的 java 开发人员,我见证了该语言的巨大发展,尤其是在并发领域。新功能的引入彻底改变了我们处理多线程编程的方式,使构建能够充分利用现代硬件的高性能应用程序变得更加容易。

completablefuture 是 java 并发工具包中最重要的补充之一。它提供了一种强大的异步计算方法,使我们能够轻松链接操作、组合结果并处理错误。我发现它在我需要编排多个独立任务的场景中特别有用。

以下是如何使用 completablefuture 的实际示例:

completablefuture usernamefuture = completablefuture.supplyasync(() -> fetchusername());
completablefuture emailfuture = completablefuture.supplyasync(() -> fetchemail());

completablefuture userfuture = usernamefuture.thencombine(emailfuture, (username, email) -> {
    return new user(username, email);
});

userfuture.thenaccept(user -> system.out.println("user created: " + user));

在此代码中,我们异步获取用户名和电子邮件,然后组合结果来创建 user 对象。 completablefuture 的美妙之处在于它允许我们以清晰、可读的方式表达这种复杂的异步逻辑。

fork/join 框架是我们并发工具库中的另一个强大工具。它专为递归分而治之问题而设计,非常适合对大型数组进行排序或处理树状数据结构等任务。该框架使用工作窃取算法,允许空闲线程从繁忙线程中“窃取”任务,确保系统资源的有效利用。

立即学习Java免费学习笔记(深入)”;

这是使用 fork/join 框架对大型数组的元素求和的示例:

public class sumtask extends recursivetask {
    private final long[] array;
    private final int start;
    private final int end;
    private static final int threshold = 10000;

    public sumtask(long[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @override
    protected long compute() {
        if (end - start <= threshold) {
            long sum = 0;
            for (int i = start; i < end; i++) {
                sum += array[i];
            }
            return sum;
        } else {
            int mid = (start + end) / 2;
            sumtask left = new sumtask(array, start, mid);
            sumtask right = new sumtask(array, mid, end);
            left.fork();
            long rightresult = right.compute();
            long leftresult = left.join();
            return leftresult + rightresult;
        }
    }
}

// usage
forkjoinpool pool = forkjoinpool.commonpool();
long[] array = new long[1000000];
// ... fill array with values
sumtask task = new sumtask(array, 0, array.length);
long sum = pool.invoke(task);

这个示例演示了我们如何使用 fork/join 框架来并行化计算密集型任务。该框架负责在可用线程之间分配工作,使我们能够专注于算法的逻辑。

并行流是构建在 fork/join 框架之上的更高级别的抽象。它们提供了一种简单的方法来并行化集合操作,从而可以轻松地利用多核处理器来执行数据处理任务。我发现并行流在处理大型数据集时特别有用,其中可以对每个元素独立执行操作。

这是使用并行流处理大量数字的示例:

list numbers = arrays.aslist(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
long sum = numbers.parallelstream()
                  .filter(n -> n % 2 == 0)
                  .maptolong(n -> n * n)
                  .sum();
system.out.println("sum of squares of even numbers: " + sum);

在此代码中,我们使用并行流来过滤偶数、对它们进行平方并对结果求和。 parallelstream() 方法自动使用 fork/join 池在多个线程之间分配工作。

stampedlock 是 java 并发实用程序的最新补充。它旨在在读取比写入频繁得多的情况下提供比 reentrantreadwritelock 更好的性能。 stampedlock 允许三种锁定模式:写入、读取和乐观读取。

以下是如何使用 stampedlock 的示例:

public class point {
    private double x, y;
    private final stampedlock sl = new stampedlock();

    void move(double deltax, double deltay) {
        long stamp = sl.writelock();
        try {
            x += deltax;
            y += deltay;
        } finally {
            sl.unlockwrite(stamp);
        }
    }

    double distancefromorigin() {
        long stamp = sl.tryoptimisticread();
        double currentx = x, currenty = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readlock();
            try {
                currentx = x;
                currenty = y;
            } finally {
                sl.unlockread(stamp);
            }
        }
        return math.sqrt(currentx * currentx + currenty * currenty);
    }
}

在此示例中,move 方法使用写锁来确保更新坐标时的独占访问。 distancefromorigin 方法使用乐观读取,它实际上并不锁定状态。如果乐观读取失败(即,如果在读取期间发生写入),它将回退到常规读取锁定。

造好物
造好物

一站式AI造物设计平台

下载

java 9 中引入的 flow api 为标准库带来了响应式编程。它提供了用于实现反应流规范的接口,允许具有非阻塞背压的异步流处理。虽然 flow api 本身相当低级,但它可以作为更高级别反应式库的基础。

这是使用 flow api 的简单示例:

public class SimplePublisher implements Flow.Publisher {
    private final List data = Arrays.asList(1, 2, 3, 4, 5);

    @Override
    public void subscribe(Flow.Subscriber subscriber) {
        subscriber.onSubscribe(new Flow.Subscription() {
            private int index = 0;

            @Override
            public void request(long n) {
                for (int i = 0; i < n && index < data.size(); i++) {
                    subscriber.onNext(data.get(index++));
                }
                if (index >= data.size()) {
                    subscriber.onComplete();
                }
            }

            @Override
            public void cancel() {
                index = data.size();
            }
        });
    }
}

public class SimpleSubscriber implements Flow.Subscriber {
    private Flow.Subscription subscription;

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
        subscription.request(1);
    }

    @Override
    public void onNext(Integer item) {
        System.out.println("Received: " + item);
        subscription.request(1);
    }

    @Override
    public void onError(Throwable throwable) {
        System.err.println("Error: " + throwable.getMessage());
    }

    @Override
    public void onComplete() {
        System.out.println("Complete");
    }
}

// Usage
SimplePublisher publisher = new SimplePublisher();
SimpleSubscriber subscriber = new SimpleSubscriber();
publisher.subscribe(subscriber);

此示例演示了使用 flow api 的简单发布者-订阅者交互。发布者发出一系列整数,订阅者一次处理一个整数。

这些并发特性显着提高了我编写高效、可扩展的 java 应用程序的能力。 completablefuture 使异步编程变得更加直观,使我能够清楚地表达复杂的工作流程。 fork/join 框架对于并行化递归算法非常有价值,而并行流则简化了批量数据处理。

stampedlock 已被证明在我需要对并发访问进行细粒度控制的场景中非常有用,尤其是在读取密集的情况下。虽然我没有直接使用 flow api,但很高兴看到响应式编程原理成为 java 标准库的一部分。

我在使用这些功能时学到的重要教训之一是为工作选择正确工具的重要性。虽然并行流很方便,但它们并不总是每个并发任务的最佳选择。有时,使用 completablefuture 或 fork/join 框架的更底层方法可以提供更好的性能和控制。

我还发现这些功能通常组合起来效果最佳。例如,我可能使用 completablefuture 来协调多个异步任务,每个异步任务在内部都使用并行流进行数据处理。或者,我可能会使用 stampedlock 来保护使用 flow api 构建的反应式应用程序中的共享状态。

需要注意的是,虽然这些功能使并发编程变得更容易,但它们并不能消除仔细设计和测试的需要。并发错误仍然可能发生,而且它们通常很微妙且难以重现。我始终确保在适当的时候使用 jcstress 等工具彻底测试我的并发代码。

总之,java 的并发增强为开发人员提供了一套强大的工具来构建高性能应用程序。通过利用 completablefuture、fork/join 框架、并行流、stampedlock 和 flow api,我们可以创建响应迅速、高效且可扩展的系统,充分利用现代多核处理器。随着 java 的不断发展,我很高兴看到该语言的未来版本中将引入哪些新的并发功能。


我们的创作

一定要看看我们的创作:

投资者中心 | 投资者中央西班牙语 | 投资者中德意志 | 智能生活 | 时代与回响 | 令人费解的谜团 | 印度教 | 精英开发 | js学校


我们在媒体上

科技考拉洞察 | 时代与回响世界 | 投资者中央媒体 | 令人费解的谜团 | 科学与时代媒介 | 现代印度教

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

832

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

738

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 3.1万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号