You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

传递给Runnable的变量为何需为final?如何解决该问题?

为什么传递给Runnable的变量需要声明为final(或有效final)?
  • 闭包的变量捕获特性:Runnable本质是闭包,会捕获外部作用域的变量。如果变量不是final/有效final,外部代码可能在Runnable异步执行前修改它,导致Runnable拿到的是变量的最新值,逻辑结果完全不可控,甚至引发并发安全问题。
  • Java的设计初衷:防止开发者误修改被捕获的变量。因为Runnable通常在其他线程执行,外部变量的变更会让异步逻辑的行为变得混乱,final/有效final能保证变量被捕获后不会再被修改,确保Runnable拿到的是稳定符合预期的值。
  • 底层实现逻辑:Java会把捕获的变量复制一份到Runnable实例中,如果变量不是final,外部修改后原变量和副本值会不一致,引发逻辑错误;final则能保证两者始终一致,从根源避免这类问题。
示例代码的问题与修复

问题分析

示例中的循环变量i每次循环都会自增,不属于有效final变量。当Runnable任务在异步线程执行时,i的值可能已经被循环修改(甚至循环结束后i等于mystr.length(),此时调用mystr.charAt(i)会抛出StringIndexOutOfBoundsException),最终输出结果不符合预期,甚至报错。

修复方案

在循环内部创建一个有效final的局部变量,保存当前循环的i值,让Runnable捕获这个稳定的变量:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NewTest {

    public static void main(String[] args) {
        String mystr = "banana";

        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < mystr.length(); i++) {
            // 用局部变量保存当前索引,该变量是有效final的
            int currentIndex = i;
            Runnable task = () -> {
                System.out.print(mystr.charAt(currentIndex));
            };

            executor.submit(task);
        }

        executor.shutdown();
    }
}

也可以用增强for循环简化代码,增强for循环中的循环变量默认是有效final的,无需额外声明:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NewTest {

    public static void main(String[] args) {
        String mystr = "banana";

        ExecutorService executor = Executors.newFixedThreadPool(10);

        // 遍历每个字符,c是有效final变量
        for (char c : mystr.toCharArray()) {
            Runnable task = () -> {
                System.out.print(c);
            };
            executor.submit(task);
        }

        executor.shutdown();
    }
}

内容的提问来源于stack exchange,提问作者Lesleyys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:33:37