-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Open
Labels
Description
描述 Bug
在 TimeUtils.java 中,为了优化性能使用了 ThreadLocal<Map<String, SimpleDateFormat>> 来缓存时间格式化器。但在执行 new SimpleDateFormat(pattern) 时,实例会隐式依赖并绑定当前线程创建时的系统全局 Locale 和 TimeZone。
在 Android 的多线程环境中,后台工作线程(如线程池)是长期存活且高度复用的。如果用户在应用运行期间切换了系统语言或跨越了物理时区,系统分配的复用旧线程仍会盲目使用 ThreadLocal 中残留的旧格式化器进行渲染。这会导致同一个应用界面上由于多线程执行出现“表现层分裂”(如部分输出法文日期,部分输出英文日期),严重破坏数据一致性和用户体验,且常规代码审查极难察觉。
- AndroidUtilCode 的版本:- 出现 Bug 的设备型号:- 设备的 Android 版本:## 相关代码
问题代码定位 (TimeUtils.java):
public static SimpleDateFormat getSafeDateFormat(String pattern) {
Map<String, SimpleDateFormat> 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 渲染错乱和数据格式异常。Reactions are currently unavailable