惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
I
InfoQ
Engineering at Meta
Engineering at Meta
Jina AI
Jina AI
Recent Announcements
Recent Announcements
T
The Blog of Author Tim Ferriss
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
D
Docker
Microsoft Security Blog
Microsoft Security Blog
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
博客园 - Franky
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog RSS Feed
WordPress大学
WordPress大学
MyScale Blog
MyScale Blog
月光博客
月光博客
罗磊的独立博客

李锋镝的博客

LiteLLM 本地代理搭建 Claude-HUD 使用文档 Kratos+ —— Kratos 主题二次开发记录 译文:如何将单体应用拆解为微服务 codebase-memory-mcp 极简完整使用指南 Claude Haiku 4.5、Claude Sonnet 4.6、Claude Opus 4.7 区别以及各自的新特性 SchedulingConfigurer详解 踩坑60+次后,我终于搞懂 Claude Skill 怎么写才会真的触发 Everything Claude Code 详细使用文档 配置Jackson使用字段而不是getter/setter来序列化和反序列化 这个域名注册整整十年了,十年时间,真快啊 Claude Code全维度实战指南:从入门到精通,解锁AI编程新范式 Apollo配置中心中的protalDB的作用是什么 org.apache.ibatis.plugin.Interceptor类详细介绍及使用 岁末 Excel2016右键新建工作表,打开时提示“因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配。”的解决办法 wordpress增加说说功能 Java 为什么有这么多 “O”? 别再背线程池的七大参数了,现在面试官都这么问 2024年11月1号 农历十月初一 我的第一个WordPress插件:Dylan Custom Plugin上线了 推荐一款比较养眼的Xshell配色方案 hnswlib installation failed 开工啦~ 阳了... MybatisCodeHelperPro激活 @Async注解的坑 新买的笔记本发货啦…… 这个中秋节感觉过的好累啊 IDEA下载源码报:Cannot connect to the Maven process. Try again later.
学艺不精啊,踩了一个Lambda的一个小坑,记录下
李锋镝 · 2025-07-30 · via 李锋镝的博客

先上代码:

package com.example.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName: AsyncTest
 * @Author: Dylan Li
 * @Date: 2025/7/25 17:43
 */
public class AsyncTest {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        AtomicReference<String> str = new AtomicReference<>();
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> new ContextAwareRunnable(
                "context()",
                () -> {
                    str.set("Hello World.");
                    System.out.println("set success");
                }
        ), executor);
        futures.add(future);

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        System.out.println("str: " + str.get());
        // 关闭线程池
        executor.shutdown();
    }

    static class ContextAwareRunnable implements Runnable {
        private final Object context;
        private final Runnable task;

        public ContextAwareRunnable(Object context, Runnable task) {
            this.context = context;
            this.task = task;
        }

        @Override
        public void run() {
            // 设置上下文(关键步骤)
            setContext(context);
            try {
                task.run(); // 执行传入的业务逻辑
            } finally {
                removeContext();
            }
        }

        private void setContext(Object context) {
            System.out.println("设置上下文:" + context);
        }

        private void removeContext() {
            System.out.println("移除上下文");
        }
    }
}

猜一下执行结果是什么?

是不是觉得很简单,打印结果肯定是:

设置上下文:context()
set success
移除上下文
str: Hello World.

如果这样想,那么恭喜你……

实际上的执行结果是:

str: null

原因很简单:

Lambda表达式的主体是new ContextAwareRunnable(...) —— 这仅仅是创建了一个Runnable实例,而没有触发它的执行逻辑。因此需要显式调用run()方法,否则ContextAwareRunnable中封装的业务逻辑永远不会执行。

具体来说:
CompletableFuture.runAsync(Runnable task) 要求传入的 task 是一个可执行的 Runnable。在上面的代码中,Lambda 表达式 () -> new ContextAwareRunnable(...) 本身是一个 Runnable,但它的逻辑只是“创建对象”,而非“执行对象的逻辑”。如果不调用 run(),这个 ContextAwareRunnable 实例就只是被创建出来,其内部的业务代码不会被触发。

解决的办法有两个:

  1. 移除Lambda表达式,代码如下:

    CompletableFuture<Void> future = CompletableFuture.runAsync(new ContextAwareRunnable(
        "context()",
        () -> {
            str.set("Hello World.");
            System.out.println("set success");
        }
    ), executor);
    futures.add(future);
  2. 调用run()方法:

    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> new ContextAwareRunnable(
        "context()",
        () -> {
            str.set("Hello World.");
            System.out.println("set success");
        }
    ).run(), executor);
    futures.add(future);

运行代码查看执行结果:

设置上下文:context()
set success
移除上下文
str: Hello World.
除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/dai-ma-ren-sheng/4494