Blankj / Blankj/AndroidUtilCode

[Bug] TimeUtils 中 ThreadLocal 缓存导致 Locale/TimeZone 状态永久滞留

Đang mở
#1,849 0 bình luận 0 reaction 1 người được giao Được @Blankj nhận Xem trên GitHub
bug
Ngôn ngữ chính
Java
Star
33.6k
Fork
10.6k
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

## 描述 Bug

在 `TimeUtils.java` 中,为了优化性能使用了 `ThreadLocal>` 来缓存时间格式化器。但在执行 `new SimpleDateFormat(pattern)` 时,实例会隐式依赖并绑定当前线程创建时的系统全局 `Locale` 和 `TimeZone`。

在 Android 的多线程环境中,后台工作线程(如线程池)是长期存活且高度复用的。如果用户在应用运行期间切换了系统语言或跨越了物理时区,系统分配的复用旧线程仍会盲目使用 ThreadLocal 中残留的旧格式化器进行渲染。这会导致同一个应用界面上由于多线程执行出现“表现层分裂”(如部分输出法文日期,部分输出英文日期),严重破坏数据一致性和用户体验,且常规代码审查极难察觉。

- AndroidUtilCode 的版本:- 出现 Bug 的设备型号:- 设备的 Android 版本:## 相关代码

**问题代码定位 (`TimeUtils.java`):**
```java
public static SimpleDateFormat getSafeDateFormat(String pattern) {
Map sdfMap = SDF_THREAD_LOCAL.get();
SimpleDateFormat simpleDateFormat = sdfMap.get(pattern);
if (simpleDateFormat == null) {
// 缺陷引爆点:隐式绑定了早期的 Locale 和 TimeZone,且被永久缓存
simpleDateFormat = new SimpleDateFormat(pattern);
sdfMap.put(pattern, simpleDateFormat);
}
return simpleDateFormat;
}

修复建议:
不能仅仅依赖 pattern 作为缓存的 Key。建议将缓存的 Key 改为 pattern + Locale.getDefault() + TimeZone.getDefault() 的复合键,或者在每次 get() 时校验当前系统的语言/时区是否发生变更,如果变更则使当前线程的缓存失效。

异常堆栈:
无崩溃堆栈。
这是一个导致微观内存维度发生静默状态漂移的逻辑缺陷,表现为多线程并发下的 UI 渲染错乱和数据格式异常。

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.