匿名内部类在多线程中访问共享变量的关键是线程安全:只能捕获final或事实final局部变量;成员变量需显式同步;应优先使用atomicinteger、concurrenthashmap等线程安全类型。

Java 中匿名内部类在多线程中访问共享变量,核心问题不是“能不能用”,而是“如何保证线程安全”。匿名内部类本身不改变变量的可见性或原子性,它只是语法糖;真正关键的是:被它捕获的变量是否可变、是否被多个线程同时读写,以及是否做了同步控制。
只能访问 final 或“事实 final”的局部变量
匿名内部类(包括 Lambda)只能引用所在方法中声明的局部变量,且该变量必须是 final 或 事实 final(即定义后未再赋值)。这是编译器限制,目的是避免变量生命周期混乱——局部变量随方法栈帧消亡,而内部类实例可能还活着。
例如以下写法会编译报错:
void doWork() {
int count = 0; // 非 final
new Thread(() -> {
count++; // ❌ 编译错误:无法修改局部变量
}).start();
}
正确做法是把需要共享的状态移到类成员字段,或使用线程安全的包装类型:
- 用
AtomicInteger、AtomicReference等替代普通基本类型或对象引用 - 将变量提升为外部类的
private volatile字段(适用于简单布尔标志或单次写入场景) - 若必须用局部变量,可声明为
final AtomicInteger count = new AtomicInteger(0),然后在内部类中调用count.incrementAndGet()
共享成员变量需显式同步
如果匿名内部类访问的是外部类的成员变量(如 this.count),那它和普通方法一样,面临典型的多线程竞态问题。Java 不会自动加锁,必须手动保障线程安全:
- 对读写操作加
synchronized块或方法(锁对象建议用私有 final 对象,避免锁 this) - 使用
ReentrantLock配合lock()/unlock()(注意 try-finally 保证释放) - 用
ConcurrentHashMap、CopyOnWriteArrayList等线程安全集合替代普通集合 -
volatile仅适用于“一个写、多个读”且无复合操作(如 i++)的场景,不能解决原子性问题
常见陷阱:看似安全,实则危险
下面这些写法容易误以为线程安全,但实际存在隐患:
-
final List<string> list = new ArrayList();</string>—— final 只保证 list 引用不变,但内容仍可被并发修改,应改用Collections.synchronizedList(new ArrayList())或CopyOnWriteArrayList -
final StringBuilder sb = new StringBuilder();—— StringBuilder 非线程安全,多线程调用append()会数据错乱,应换用StringBuffer或加锁 - 在匿名内部类里直接 new 对象并修改其状态(如 new User().setName("A")),若该对象被多个线程共享引用,同样需要同步
推荐实践:优先用 Lambda + 线程安全类型
现代 Java 更倾向用 Lambda 表达式替代匿名内部类,语义更简洁。关键是配合正确的共享数据结构:
- 计数类场景:用
AtomicInteger counter = new AtomicInteger(0),Lambda 中调用counter.incrementAndGet() - 收集结果:用
ConcurrentLinkedQueue<result></result>或CopyOnWriteArrayList,避免同步块 - 需要复杂逻辑时,把共享状态封装进一个独立的线程安全工具类,匿名类/Lambda 只负责调用其方法
- 避免在多线程中让匿名内部类持有对外部对象的强引用,防止内存泄漏(尤其在长生命周期线程池中)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











