AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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

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

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

关注

评论

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

C#-使用Consul

kdyonly

C#

助力游戏厂商稳健发展,华为云大数据解决方案高效赋能!

与时俱进的时代

“上云”成本低,稳定可靠!华为云OBS助力企业解决数据存储难题

与时俱进的时代

存储数据不要愁,华为云来帮你!

与时俱进的时代

2022卡塔尔世界杯专题分析

易观分析

世界杯 体育

云渲染一张图大概多久?云渲染快吗?

Renderbus瑞云渲染农场

云渲染

什么样的魔法棒,能让AI魔法师一夜成名?

白洞计划

极狐GitLab include 语法减少 CI/CD Pipeline 代码冗余,提升构建效率

极狐GitLab

DevOps CI/CD pipeline 极狐GitLab include

华为云CDN:海量存储+过硬本领为用户带来更优体验

科技说

什么样的魔法棒,能让AI魔法师一夜成名?

脑极体

MatrixDB v4.6.0 发布,查询性能和图形化操作界面全面升级!

YMatrix 超融合数据库

Prometheus 存储引擎 超融合数据库 YMatrix MatrixGate

不止于快,华为云CDN加速服务为企业提供安全加速环境

科技说

不止稳定快速,看华为云CDN如何在国际云服务市场中“分蛋糕”

爱科技的水月

华为云CDN加速服务,让企业用户上网“走高速”

爱科技的水月

华为云CDN加速服务助你开启网络加速时代

爱科技的水月

Oracle数据库安装配置详细教程汇总(含11g、12c、18c、19c、21c)

墨天轮

数据库 oracle 升级 安装 & 部署

华为云CDN加速服务的精细化管理,让加速变得简单起来

科技说

不止于快,华为云CDN加速服务对OBS桶文件加速的超实用技巧

爱科技的水月

华为云CDN加速,如何助力企业更好发展?

爱科技的水月

软件测试 / 测试开发 / BAT大厂都在用的Docker。学会这三招,面试、工作轻松hold住

测试人

Docker 容器 软件测试 测试开发 环境搭建

支持随时畅玩3A游戏,华为云大数据助力游戏厂商快速稳健发展!

与时俱进的时代

华为云CDN加速,为企业开启高效且安全的加速环境

科技说

干货|无源元件之——电感基础知识(详解)

元器件秋姐

科普 电感器 电感 电感元件 电子知识

APISIX Ingress 对 Gateway API 的支持和应用

API7.ai 技术团队

云原生 APISIX API Gateway Ingress Controller

小米封杨:工业设备预测性维护及时序数据库选型

YMatrix 超融合数据库

工业4.0 超融合数据库 预测性维护 设备预测性维护 YMatrix

华为云CDN,如何助力智能新媒体转型

科技说

存储空间不够大?试试华为云OBS对象存储服务

与时俱进的时代

何惧内卷?华为云对象存储服务OBS工具随便拿出一个都很能打

与时俱进的时代

华为云大数据BI解决方案助企业突破数据壁垒,加快企业数字化建设

与时俱进的时代

华为云微服务引擎0停机迁移Nacos?它是这样做的

科技之光

【电商行业必备神器】轻松备战“双十一”,华为云OBS值得拥有

与时俱进的时代

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