会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 小白科普:“无状态”那点事儿!

小白科普:“无状态”那点事儿

时间:2025-11-05 11:44:19 来源:益强数据堂 作者:应用开发 阅读:610次

软件大师正在闭目修炼,无状态 最小的小白一名弟子慢慢走了进来。

弟子:大师,科普弟子有一事不明,那点甚是事儿烦恼。

大师:说来听听,无状态让为师给你排解一下。小白

弟子:我经常听师兄们争论‘无状态’,科普 说‘无状态’在软件编程中是那点好事情, 可是事儿到底什么是状态? 什么是无状态?

大师睁开眼来,写下一行字:  y=f(x),无状态然后又闭上了眼睛。小白

弟子:(奇怪地问道)这不就是科普一个函数吗?我初中就学过, 给定一个x,那点函数经过计算(比如求平方)就能得到一个y。事儿

大师:没错,这就是一个纯函数,对于相同的输入,总是得到相同的输出,不依赖于外界的状态。

弟子:这也没什么啊!

大师:你想想,免费信息发布网要是有多个线程在一个CPU上并发调用这个函数,会不会有问题?

弟子:不会。

大师:如果是有多个线程在多个CPU上并行执行这个函数,会不会有问题?

弟子:不会。

大师:为什么?

弟子:因为每次调用都不会在这个函数中保留数据, 调用完了就完了,每一次调用都是崭新的调用,并且***次和***百次之间没有任何关系。

大师:因为那个函数不保存状态,所以无论是并发还是并行,都没有问题。

弟子:嗯,明白。

大师:你再想想你常用的HTTP,每次访问一个静态HTML页面的时候,对于服务器来讲,是不是就相当于调用了一个函数,函数输入:一个URL路径, 函数输出:HTML页面。

弟子:那这么说来,这个服务器也不会记录每次请求的是谁,WordPress模板只要执行这个函数调用就可以了。

大师:你说说,这样的HTTP协议有什么好处?

弟子:由于没有状态,如果一个服务器访问量过大,我可以轻松地添加新的服务器来处理请求。

大师:“孺子可教也,这就是所谓水平扩展(scale-out)。

弟子:水平扩展? 难道还有垂直扩展(scale-up)?

大师:对,垂直扩展就是通过增加CPU,内存,硬盘等方式来提高单个服务器的处理能力。由于单台机器总是有上限的,所以想应对海量用户的访问,提高可用性,还得靠水平扩展。现在你体会到无状态的好处了吧?

弟子:明白了,大师,在服务器端无状态确实是个美好的世界, 可是现实很残酷,没有状态不行啊,一个人登录了,高防服务器我们得记住他是谁吧,他往购物车里加入商品,我们也得记下来吧。

大师:那你们怎么记啊?

弟子:肯定用Session来保存状态啊!

大师:服务器一旦引入状态,就没法轻松地水平扩展了吧!

弟子:是的,该怎么办?

大师:这里边办法很多,例如让状态在各个服务器之间进行复制,但最常用的是把状态转移存储到另外一个地方,尽量服务器恢复到无状态的y=f(x)。

(注:实际情况下,图中服务器之前还有负责负载均衡的服务器)

弟子:奥,这样一来,又可以水平扩展了! 对了大师,我刚才听到师兄们提到‘无状态对象’,他们说就是一个对象没有实例变量,或者实例变量是final的。这么说对吧?

大师:嗯,这种情况下,说‘无状态对象’ 有点不准确了,更准确的词是‘不可变对象’(Immutable Object),比如:

public final class Complex{     private final int a;     private final int b;     public Complex(int a, int b){         this.a = a;         this.b = b;     }     public Complex add(Complex other){         return new Complex(a + other.a, b+other.b);     } } 

弟子:奥,这个类的对象一旦创建,就不能再改变了, 我看到了那个add方法,它不是对现有对象的修改,而是返回了一个全新的对象。

大师:这样的话当多个线程调用add对象的时候,都是线程安全的。 我这里有一副图画,是LISP大师送给我的,形象地展示了可变 vs 不可变, 你拿去吧:

弟子:那代价也有点大啊,每次都创建新对象!我们用Spring,其中的Controller, Service被大量地并发调用,肯定不能用这种方法了。

大师:是的,你们用的Controller, Service 默认都是单例,运行期只有一个实例,他们的方法应该是y=f(x)这样的无状态方法,轻易不要在里边放置共享的实例变量,要不然多线程并发操作就可能出问题了。

弟子:可是我们的Controller 一般都要放个Service的实例变量啊 ,比如这个LoginController中的userService, 多个线程同时访问这个共享的userService,岂不就出问题了?

@Controller public class LoginController {     @Autowired     private UserService userService;     ......对userService的使用略...... } 

大师:你误入歧途了,把无状态和无共享的实例变量画了等号,你想想,如果LoginController调用的userService 的方法也是类似 y=f(x), 会有线程安全问题吗?

弟子:嗯...... 好像是没有问题。 无论是Controller还是Service都是纯函数调用而已。 但是如果确实需要共享的变量该怎么办?

大师:很简单,使用ThreadLocal,把这个变量存到各个线程当中,让他们互不干扰,就线程安全了。

【本文为专栏作者“刘欣”的原创稿件,转载请通过作者微信公众号coderising获取授权】

戳这里,看该作者更多好文

(责任编辑:数据库)

上一篇:Ubuntu 14.04 LTS是最新的Ubuntu长期支持版本,拥有多项改进并添加了新版本软件。假如你已升级至Ubuntu 14.04,在体验新版本的同时还需要知道5件事。1、禁用集成的Amazon搜索Ubuntu Dash集成了Amazon搜索结果,当你在Dash中进行搜索时,搜索将会发送到Ubuntu服务器,然后返回Amazon搜索结果。你可能不希望发送搜索到Ubuntu服务器,这时就需要禁用该服务。打开设置中的安全和隐私选项,找到搜索标签页并关闭包含在线搜索结果即可。该方法会禁用所有在线搜索结果,假如你仅需禁用Amazon搜索结果,打开终端输入下面的命令:复制代码代码如下:sudo apt-get remove unity-lens-shopping同时还需要将启动器中的Amazon链接图标移除。2、禁用全局菜单Ubuntu 14.04提供了关闭全局菜单的功能,具体设置方法可参看如何启用Ubuntu 14.04的本地菜单。3、Ubuntu One已被移除Ubuntu One是Ubuntu中集成的云服务,Canonical现在已经宣布了停止Ubuntu One服务。你可以使用Dropbox来替代Ubuntu One,Dropbox是流行的云存储服务,并且提供了Linux客户端。4、集成的Web应用不能正常工作Ubuntu提供了Web应用功能,通过该功能你能方便地访问你喜欢的网站。在Ubuntu 14.04中Web应用将默认使用与Ubuntu Mobile相同的浏览器打开,但该浏览器并不能正常工作。假如你想使用Web应用功能,你可以使用Chrome浏览器来实现相同的功能。5、TRIM默认开启TRIM是一项优化SSD性能的服务,在Ubuntu 14.04中TRIM默认为开启状态,但只支持Intel和Samsung的SSD。
下一篇:努比亚与华为的拍照效果对比(揭秘努比亚和华为的摄影差异,寻找最佳拍照手机)
推荐内容
  • 佳能180微距镜头(揭开佳能180微距镜头的神奇魅力,探索微距摄影的无限可能)
  • 亚马逊贝佐斯:如何用遗憾最小化框架做艰难的决定?
  • Elasticsearch 在地理信息空间索引的探索和演进
  • 激活数据价值,探究DataOps下的数据架构及其实践
  • 如何在电脑上注册对峙账号(简单易懂的教程,让您快速注册对峙账号)
  • 数字化时代的科技双模,双模IT成为过去式