写点什么

代码之丑(十二)-- 无状态方法

  • 2012-06-17
  • 本文字数:1303 字

    阅读完需:约 4 分钟

诸位 Java 程序员,想必大家对 SimpleDateFormat 并不陌生。不过,你是否知道,SimpleDateFormat 不是线程安全的(thread safe)。这意味着,下面的代码是错误的:

复制代码
class Sample {
private static final DateFormat format = new SimpleDateFormat("yyyy.MM.dd");
public String getCurrentDateText() {
return format.format(new Date());
}
}

从功能的角度上看,单独执行这段代码是没有问题的,但放到多线程环境下,因为 SimpleDateFormat 不是线程安全的,这段代码就会出错。所以,要想让这段代码正确,我们只要稍做微调:

复制代码
public class Sample {
public String getCurrentDateText() {
return new SimpleDateFormat("yyyy.MM.dd").format(new Date());
}
}

不知你是否注意到,这里的调整只是由原来的共享 format 这个变量,变成了每次调用这个方法时创建出一个新的 SimpleDateFormat 变量。

作为一个专业程序员,我们当然知道,相比于共享一个变量的开销要比每次创建小。之所以我们必须这么做,是因为 SimpleDateFormat 不是线程安全的。但从 SimpleDateFormat 提供给我们的接口上来看,实在让人看不出它与线程安全有和相干。那接下来,我们就要打开 JDK 的源码,看一下其中的代码之丑。

如果你手头没有 JDK 的源码,这里是个不错的参考。

在 format 方法里,有这样一段代码:

复制代码
calendar.setTime(date);

其中,calendar 是 DateFormat 的 protected 字段。这条语句改变了 calendar,稍后,calendar 还会用到(在 subFormat 方法里),而这就是引发问题的根源。

想象一下,在一个多线程环境下,有两个线程持有了同一个 SimpleDateFormat 的实例,分别调用 format 方法:

  1. 线程 1 调用 format 方法,改变了 calendar 这个字段。
  2. 中断来了。
  3. 线程 2 开始执行,它也改变了 calendar。
  4. 又中断了。
  5. 线程 1 回来了,此时,calendar 已然不是它所设的值,而是走上了线程 2 设计的道路。
  6. BANG!!! 稍微花点时间分析一下 format 的实现,我们便不难发现,用到 calendar,唯一的好处,就是在调用 subFormat 时,少了一个参数,却带来了这许多的问题。其实,只要在这里用一个局部变量,一路传递下去,所有问题都将迎刃而解。

这个问题背后隐藏着一个更为重要的问题:无状态。

无状态方法的好处之一,就是它在各种环境下,都可以安全的调用。衡量一个方法是否是有状态的,就看它是否改动了其它的东西,比如全局变量,比如实例的字段。format 方法在运行过程中改动了 SimpleDateFormat 的 calendar 字段,所以,它是有状态的。

写程序,我们要尽量编写无状态方法。

作者简介

郑晔,ThoughtWorks 公司首席咨询师,拥有十多年企业级软件开发经验,热衷于探索各种程序设计语言在真实软件开发中所能发挥的威力,致力于探寻合理的软件开发方式,加入 ThoughtWorks 公司后,投入到敏捷开发方法的实践之中,为其他公司提供敏捷开发方法方面的咨询服务。他的 blog 是梦想风暴,其微博是 @dreamhead

查看原文:代码之丑(十二)


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-06-17 21:306976
用户头像

发布了 22 篇内容, 共 14.0 次阅读, 收获喜欢 49 次。

关注

评论

发布
暂无评论
发现更多内容

鸿蒙应用开发从入门到入行 - 篇7:http网络请求

猫林老师

鸿蒙 HarmonyOS 鸿蒙应用开发 鸿蒙原生应用开发 HarmonyOS NEXT

ATB是什么?

zjun

CANN Ascend 大模型推理

AIGC对本地配置要求高吗,云桌面如何实现一键镜像?

青椒云桌面

AIGC云桌面 AIGC云电脑 sd云端部署

ATB算子实现原理解读

zjun

CANN Ascend 大模型推理

AscendC从入门到精通系列(一)初步感知AscendC

zjun

算子 大模型 CANN AscendCL Ascend

0基础跟练!代码小白也能搭建自己的专属 AI 聊天助手

豆包MarsCode

AI 聊天机器人 AI编程 聊天助手 豆包MarsCode

uniapp开发鸿蒙,是前端新出路吗?

猫林老师

前端 HarmonyOS

Kafka 迁移 AutoMQ 时 Flink 位点管理的挑战与解决方案

AutoMQ

Antares Auto-Tune Pro for Mac(音调校正) 11.0 激活版

小玖_苹果Mac软件

强大Raw格式图像ps插件Adobe Camera Raw for Mac中文激活

小玖_苹果Mac软件

蓝宝石插件套装Boris FX Sapphire mac激活版 支持AE PS AVX OFX等

小玖_苹果Mac软件

还在为入门鸿蒙效率慢而困惑?不妨试试开发学习神器 - AI辅助编程

猫林老师

鸿蒙 HarmonyOS 鸿蒙应用开发 鸿蒙原生应用开发 HarmonyOS NEXT

1685页Java面试题大全(整理版)3000+面试题附答案详解,最全面详细

采菊东篱下

编程 计算机 java面试

开辟新蓝海 华为坤灵剑指中小企业安全增量市场

Geek_2d6073

3D渲染与动画制作的创意利器 KeyShot 2024 for mac中文激活版

小玖_苹果Mac软件

Bodymovin for Mac (AE动画导出json工具) v5.12.1英文激活版

小玖_苹果Mac软件

Axure RP 10 for Mac中文激活版:高效原型设计软件

小玖_苹果Mac软件

VMware ESXi 8.0U3c Unlocker & OEM BIOS 标准版和厂商定制版

sysin

esxi

【万字长文】MarsCode结合 Manim 打造炫酷的算法演示动画

战场小包

Python AI 代码生成 AIGC

如何使用Ascend的ATB加速库?

zjun

CANN Ascend 大模型推理

如何在c++侧编译运行一个aclnn(AOL)算子?

zjun

算子 大模型 CANN 昇腾 Ascend

HarmonyOS鸿蒙开发 - 解决上下两栏白边 - 沉浸式效果

猫林老师

HarmonyOS 鸿蒙应用开发 鸿蒙原生应用开发 HarmonyOS NEXT

开源云原生数据仓库 ByConity测试

多啦A梦

ByConity

Ascend推理组件MindIE LLM

zjun

推理模型 Ascend 大模型推理

智能加氢站站控系统(源码+文档+部署+讲解)

深圳亥时科技

VMware ESXi 8.0U3c Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

sysin

esxi

智谱清言英特尔酷睿Ultra专享版发布,离线模型玩转AIPC

E科讯

牛客网2024版Java最新面试宝典(附答案解析)正式开源!

采菊东篱下

程序员 java面试

ATB概念之:算子tiling

zjun

CANN 数据切片 Ascend 大模型推理

代码之丑(十二)--无状态方法_Java_郑晔_InfoQ精选文章