Blankj / Blankj/AndroidUtilCode

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

Abierto
#1,849 0 comentarios 0 reacciones 1 asignado Reclamado por @Blankj Ver en GitHub
bug
Lenguaje dominante
Java
Estrellas
33.6k
Forks
10.6k
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

## 描述 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 渲染错乱和数据格式异常。

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.