写点什么

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

  • 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:307174
用户头像

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

关注

评论

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

在安卓应用市场上架需要注意什么?

InfoQ IT百科

即时通讯系统搭建IM聊天社交软件开发

a13823115807

目前主流的手机SOC芯片都有哪些?

InfoQ IT百科

手机 SOC 芯片

B站可以称为中国的YouTube吗?

InfoQ IT百科

一文读懂PlatoFarm新经济模型以及生态进展

西柚子

「查缺补漏」,DDD 核心概念梳理

悟空聊架构

DDD 领域驱动 4月日更 悟空聊架构 4月月更

架构实战毕业总结

王大胖

数字化时代,企业运维面临现状及挑战分析解读

云智慧AIOps社区

大数据 运维 数字化时代 大数据运维

智慧公安二维码定位报警系统开发 移动警务app

a13823115807

LCD和OLED屏幕有哪些异同

InfoQ IT百科

数字化时代,SaaS软件如何成为国产化替代的轻骑兵?

小炮

Android ANR分析(trace文件的产生流程)

北洋

4月月更

应用要在AppStore上线,需要满足什么条件?

InfoQ IT百科

APP评测的网站有哪些?

InfoQ IT百科

读书破万“卷”:国民阅读洞察2022

易观分析

阅读 文学

返璞归真,多方安全计算要回归到“安全”的本源考虑

易观分析

多方安全计算

一文读懂PlatoFarm新经济模型以及生态进展

小哈区块

Mini LED有哪些优势

InfoQ IT百科

终极套娃 2.0|云原生 PaaS 平台的可观测性实践分享

尔达Erda

微服务 云原生 可观测性 经验分享 实践

首届船海数据智能应用创新大赛赛事公告

科技热闻

目前主流的手机屏幕类型都有哪些

InfoQ IT百科

手机

关于Signal Catcher线程中对线程的理解

北洋

4月月更

SWOOLE高性能内存数据库的使用和配置教程

CRMEB

外包学生管理系统架构方案

Trent

架构文档 架构训练营

Clubhouse为什么不火了?

InfoQ IT百科

万有导航:简洁实用的综合导航网站

小炮

RAM运行内存是什么

InfoQ IT百科

手机

百度云盘好用还是阿里云盘好用?

InfoQ IT百科

CRM系统可以帮助改善客户体验吗?

低代码小观

CRM 客户关系管理 企业管理系统 CRM系统 客户关系管理系统

App和小程序有哪些区别?

InfoQ IT百科

昊天旭辉签约长扬科技,携手共建工业互联网安全新生态

极客天地

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