成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

小白科普:“無狀態”那點事兒

開發 開發工具
垂直擴展就是通過增加CPU,內存,硬盤等方式來提高單個服務器的處理能力。由于單臺機器總是有上限的,所以想應對海量用戶的訪問,提高可用性,還得靠水平擴展?,F在你體會到無狀態的好處了吧?

軟件大師正在閉目修煉, 最小的一名弟子慢慢走了進來。

弟子:大師,弟子有一事不明,甚是煩惱。

大師:說來聽聽,讓為師給你排解一下。

弟子:我經常聽師兄們爭論‘無狀態’, 說‘無狀態’在軟件編程中是好事情, 可是到底什么是狀態? 什么是無狀態?

大師睜開眼來,寫下一行字:  y=f(x),然后又閉上了眼睛。

弟子:(奇怪地問道)這不就是一個函數嗎?我初中就學過, 給定一個x,函數經過計算(比如求平方)就能得到一個y。

大師:沒錯,這就是一個純函數,對于相同的輸入,總是得到相同的輸出,不依賴于外界的狀態。

弟子:這也沒什么啊!

大師:你想想,要是有多個線程在一個CPU上并發調用這個函數,會不會有問題?

弟子:不會。

大師:如果是有多個線程在多個CPU上并行執行這個函數,會不會有問題?

弟子:不會。

大師:為什么?

弟子:因為每次調用都不會在這個函數中保留數據, 調用完了就完了,每一次調用都是嶄新的調用,并且***次和***百次之間沒有任何關系。

大師:因為那個函數不保存狀態,所以無論是并發還是并行,都沒有問題。

弟子:嗯,明白。

大師:你再想想你常用的HTTP,每次訪問一個靜態HTML頁面的時候,對于服務器來講,是不是就相當于調用了一個函數,函數輸入:一個URL路徑, 函數輸出:HTML頁面。

弟子:那這么說來,這個服務器也不會記錄每次請求的是誰,只要執行這個'函數調用'就可以了。

大師:你說說,這樣的HTTP協議有什么好處?

弟子:由于沒有狀態,如果一個服務器訪問量過大,我可以輕松地添加新的服務器來處理請求。

大師:“孺子可教也,這就是所謂水平擴展(scale-out)。

弟子:水平擴展? 難道還有垂直擴展(scale-up)?

大師:對,垂直擴展就是通過增加CPU,內存,硬盤等方式來提高單個服務器的處理能力。由于單臺機器總是有上限的,所以想應對海量用戶的訪問,提高可用性,還得靠水平擴展。現在你體會到無狀態的好處了吧?

弟子:明白了,大師,在服務器端無狀態確實是個美好的世界, 可是現實很殘酷,沒有狀態不行啊,一個人登錄了,我們得記住他是誰吧,他往購物車里加入商品,我們也得記下來吧。

大師:那你們怎么記啊?

弟子:肯定用Session來保存狀態??!

大師:服務器一旦引入狀態,就沒法輕松地水平擴展了吧!

弟子:是的,該怎么辦?

大師:這里邊辦法很多,例如讓'狀態'在各個服務器之間進行復制,但最常用的是把狀態轉移存儲到另外一個地方,盡量服務器恢復到無狀態的'y=f(x)'。

(注:實際情況下,圖中服務器之前還有負責負載均衡的服務器)

弟子:奧,這樣一來,又可以水平擴展了! 對了大師,我剛才聽到師兄們提到‘無狀態對象’,他們說就是一個對象沒有實例變量,或者實例變量是final的。這么說對吧?

大師:嗯,這種情況下,說‘無狀態對象’ 有點不準確了,更準確的詞是‘不可變對象’(Immutable Object),比如:

  1. public final class Complex{ 
  2.     private final int a; 
  3.     private final int b; 
  4.     public Complex(int a, int b){ 
  5.         this.a = a; 
  6.         this.b = b; 
  7.     } 
  8.     public Complex add(Complex other){ 
  9.         return new Complex(a + other.a, b+other.b); 
  10.     } 

弟子:奧,這個類的對象一旦創建,就不能再改變了, 我看到了那個add方法,它不是對現有對象的修改,而是返回了一個全新的對象。

大師:這樣的話當多個線程調用add對象的時候,都是線程安全的。 我這里有一副圖畫,是LISP大師送給我的,形象地展示了可變 vs 不可變, 你拿去吧:

弟子:那代價也有點大啊,每次都創建新對象!我們用Spring,其中的Controller, Service被大量地并發調用,肯定不能用這種方法了。

大師:是的,你們用的Controller, Service 默認都是單例,運行期只有一個實例,他們的方法應該是y=f(x)這樣的無狀態方法,輕易不要在里邊放置共享的實例變量,要不然多線程并發操作就可能出問題了。

弟子:可是我們的Controller 一般都要放個Service的實例變量啊 ,比如這個LoginController中的userService, 多個線程同時訪問這個共享的userService,豈不就出問題了?

  1. @Controller 
  2. public class LoginController { 
  3.     @Autowired 
  4.     private UserService userService; 
  5.     ......對userService的使用略...... 

大師:你誤入歧途了,把無狀態和無共享的實例變量畫了等號,你想想,如果LoginController調用的userService 的方法也是類似 y=f(x), 會有線程安全問題嗎?

弟子:嗯...... 好像是沒有問題。 無論是Controller還是Service都是純函數調用而已。 但是如果確實需要共享的變量該怎么辦?

大師:很簡單,使用ThreadLocal,把這個變量存到各個線程當中,讓他們互不干擾,就線程安全了。

【本文為51CTO專欄作者“劉欣”的原創稿件,轉載請通過作者微信公眾號coderising獲取授權】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2022-05-26 15:30:21

Spring AOP框架

2020-01-03 07:57:39

UDPTCP網絡協議

2013-12-26 13:35:39

2015-12-08 14:49:13

SDN軟件定義網絡

2017-09-12 08:03:29

數據庫MySQL主庫

2011-12-26 11:13:24

密碼

2013-09-17 10:37:03

AOPAOP教程理解AOP

2022-05-26 09:03:39

AOP編程

2023-12-04 11:02:53

C++空類

2012-03-12 21:23:47

Windows pho

2021-04-13 09:12:45

網絡設備無線路由器交換機

2012-04-17 11:21:50

Java

2013-12-04 09:46:56

Hyper-VNUMA

2017-04-19 08:35:34

2018-05-17 09:46:40

apachenginx阻塞

2024-04-30 11:14:19

KubernetesReplicaSet數量

2017-09-11 15:17:01

分布式集群負載均衡

2024-11-22 10:45:20

2025-03-12 03:00:00

2017-09-19 15:22:44

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美在线免费观看 | 亚洲国产精品久久久久 | 国产精品久久久久久一区二区三区 | 在线看av的网址 | 91免费视频| 亚洲精品久久久久久宅男 | 特黄色毛片 | 黄色免费av| 亚洲国产成人精品久久 | av在线免费观看网址 | 成人久久18免费网站麻豆 | 久久三区| 久草a√| 伊人无码高清 | 久久久无码精品亚洲日韩按摩 | 国产一区久久久 | 亚洲综合电影 | 亚洲a视| 在线一区二区三区 | 国产一级片网站 | 超碰超碰| 亚洲视频免费观看 | 国产羞羞视频在线观看 | 盗摄精品av一区二区三区 | 天天av综合 | 亚洲国产精品久久久 | 久久久精品视频一区二区三区 | 成人免费视频网站在线看 | 日韩视频国产 | 人人精品 | 午夜av成人| 亚洲看片网站 | 免费影视在线观看 | 日韩三级在线观看 | 免费在线观看一区二区三区 | 日韩伦理一区二区 | 欧美视频中文字幕 | 国产精品综合久久 | 人人亚洲 | 久久精品亚洲国产 | 久久久久久成人 |