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

旺財和小強的三生三世

企業動態
旺財和小強是線程池的兩個線程, 他們經常做的工作就是對一個數加加減減,用人類的話來說就是存款,取款。

 ***世

旺財和小強是線程池的兩個線程, 他們經常做的工作就是對一個數加加減減,用人類的話來說就是存款,取款。

  1. public class Account{ 
  2.    private int balance; 
  3.    public synchronized void deposit(int amt){ 
  4.        balance += amt; 
  5.    } 
  6.  
  7.    public synchronized void withdraw(int amt){ 
  8.        if(balance >= amt){ 
  9.            balance -= amt; 
  10.        } 
  11.        throw new RuntimeException("insufficent blance"); 
  12.    } 

(友情提示,可左右滑動,下同)

每次進行存款,取款操作的時候,他們兩個都需要獲得一把鎖,這樣就能保證同一時刻只有一個人在修改,不會出亂子。

這一天,他們倆又遇到了一個叫做轉賬的操作:

  1. public void transfer(Account from,Account toint amt){ 
  2.    synchronized(from){ 
  3.        synchronized(to){ 
  4.            from.withdraw(amt); 
  5.            to.deposit(amt); 
  6.        } 
  7.    } 

旺財說:“這個程序員不錯,考慮得挺周全。轉賬的時候把兩個賬戶都鎖住了,安全!”

小強說:“沒錯,執行吧。”

旺財這個線程從A向B轉賬 , 與此同時,小強從B向A轉賬

令旺財和小強沒有想到的是,居然出現了死鎖。

 

類似的事件發生不少, 線程池的線程用光了,Tomcat被迫重啟,這個世界毀滅了。

第二世

新生代的旺財和小強從線程池中出來, Tomcat老大給他們講了上一代旺財和小強的故事, 對他們諄諄教導:“做轉賬操作的時候一定要小心,別死鎖了!”

旺財和小強有點兒憤憤不平:“這我們倆也控制不了啊,這要看程序員寫的代碼,以及操作系統中的線程調度啊!”

不滿歸不滿,他倆還是有點小期待,想看看可怕的轉賬代碼到底怎么樣。

沒過多久, 他倆就如愿了:

  1. public static final Object lock = new Object(); 
  2. public void transfer(Account from,Account toint amt){ 
  3.    int fromHash = System.identityHashCode(from); 
  4.    int toHash = System.identityHashCode(to); 
  5.    if(fromHash > toHash){ 
  6.        synchronized(from){ 
  7.            synchronized(to){ 
  8.                from.withdraw(amt); 
  9.                to.deposit(amt); 
  10.            } 
  11.        } 
  12.    } 
  13.    else if(toHash > fromHash){ 
  14.        synchronized(to){ 
  15.            synchronized(from){ 
  16.                from.withdraw(amt); 
  17.                to.deposit(amt); 
  18.            } 
  19.        } 
  20.    } 
  21.    else { 
  22.        synchronized(lock){ 
  23.            synchronized(from){ 
  24.                synchronized(to){ 
  25.                    from.withdraw(amt); 
  26.                    to.deposit(amt); 
  27.                } 
  28.            } 
  29.        } 
  30.    } 

看到這樣的代碼, 旺財倒吸了一口氣,撓著頭說:“搞什么鬼,轉個賬都這么麻煩!”

小強說:“老大不是說了嗎,上一代線程老是在轉賬這里出錯,于是代碼就重寫了。你看,這一次寫得就很嚴謹了,每一次都會去比較兩個賬戶的大小(通過hash code),誰大就先獲得誰的鎖。 ”

旺財說:“奧,相當于把賬戶給排了序,假設賬戶A大于賬戶B , 那我們倆轉賬的時候,每次都先獲得A的鎖,這樣就不會互相等待了。 ”

 

“沒錯,還有一個特殊情況,如果這兩個賬戶的hash code 相同,那就再去競爭另外一個特殊的鎖,誰搶到誰就可以先執行。另一個就在那里等待。”

旺財和小強這次順利地把轉賬給執行完了,回去給Tomcat匯報了一遍。

Tomcat老大感慨地說:“有這么復雜的代碼,可見使用‘共享內存’的方式來并發編程很不容易啊!”

“共享內存?”

“對啊,你看這些賬戶的數據,每個線程都可以訪問,不就是共享內存嗎, 為了能夠安全訪問,只有來‘加鎖’了。 古人說,這個世界上有兩種構建軟件的方式,一種方法是使其足夠簡單以至于不存在明顯的缺陷,另外一種是使其足夠復雜以至于看不出有什么問題。我很擔心啊, 現在這個系統就屬于第二種,不知道有多少坑在等著我們呢!”

(碼農翻身: 實際上這句話是托尼·霍爾說的)

老大不幸言中,終于有一天,這個復雜到看不出問題的系統崩潰了,這個世界又毀滅了。

第三世

第三代的旺財和小強從線程池出來。

出發前,Tomcat老大把前兩代線程遇到的問題給他們說了一遍,威脅說:如果再出現死鎖,小心你們兩個的腦袋!

旺財和小強戰戰兢兢,如履薄冰地執行代碼。

最終他們還是遇到了傳說中的可怕的轉賬代碼:

  1. def transfer(from: Account, to: Account,amt:Int){ 
  2.    atomic{ 
  3.        from.withdraw(amt); 
  4.        to.deposit(amt); 
  5.    } 

旺財非常吃驚:“這是什么代碼?不是Java?”

小強說:“嗯,不是Java ,是Scala寫的,這是運行在JVM上的一個語言。”

(碼農翻身注:實際上JVM線程能看到的只是Java 字節碼,根本看不到源碼,也就不知道是Java寫的代碼,還是Scala寫的代碼, 這里只是為了展示方便。)

旺財說:“怎么這么簡單,會不會出問題?那個atomic是怎么回事?表示原子執行?”

小強也有點懵,不敢貿然去執行:“咱們還是去問Tomcat老大吧。”

Tomcat看了一眼:“人類程序員又改代碼了啊,開始使用Software Transaction Memory(STM)了。 去把STM老頭兒叫來,讓他給你倆解釋。”

STM老頭兒滿臉滄桑:“放心執行吧,只要你把代碼放到atomic中,我就能保證他們像事務一樣,實現ACID,哦不,D(持久化)實現不了,這些數據都是在內存中的。”

“這有什么用? ”

“可以讓你們倆安全地并發執行啊?”

旺財和小強面面相覷,這連鎖都沒有,還安全地并發?

“別看沒有鎖,” STM老頭兒說,“在atomic代碼開始執行的時候,我會記錄下代碼塊涉及到的數據的值(復制了一份),然后才真正執行,執行完了要‘提交’, 這時候我會看看那些數據的值是否也被別的線程改動了,如果有改動,那本次改動就撤銷,重新從代碼開始處執行。 ”

老頭兒畫了一個圖,展示旺財從賬戶A給賬戶B轉20元, 與此同時小強從B向A轉30元。

 

還真是,沒有加鎖就安全地完成了兩個并發操作。

當然,老頭兒為了實現這個atomic操作,背后偷偷做了不少事情:復制數據,提交,重復執行。

旺財想起來自己曾經執行過一下Java 的Compare and swap的代碼,說道:“你這不就是CAS嘛!”

老頭兒說:“原理上類似,都是樂觀鎖,不過我這個方式和數據庫的事務更加類似,所以叫做Software Transaction Memory。”

小強想了想,說道:“不對啊,atomic是個代碼塊,里邊可能有很多代碼,涉及到很多class, 你怎么知道哪些字段需要被STM管理起來啊!”

STM老頭兒說:“這真是個好問題,實際上,需要程序員們來告訴我。比如使用這個方法”

  1. class Account(val initialBalance : Int){ 
  2.  val balance = Ref(initialBalance) 
  3.  ...... 

“看到那個Ref沒有,這就是一種辦法,通過它,我就知道這個balance的字段需要讓我管理起來,在atomic代碼塊運行的時候,就需要復制它的值,比較它的值。”

“明白了,但是‘重復執行’有問題啊,假設程序員張大胖是這么寫代碼的:”

  1. def transfer(from: Account, to: Account,amt:Int){ 
  2.     atomic{ 
  3.         from.withdraw(amt); 
  4.         ...在這里執行一些其他操作,例如打印日志,發送郵件..... 
  5.         to.deposit(amt); 
  6.     } 

“這其中有一些打印日志,發送郵件的操作,那你重復執行,豈不會執行很多次,就完全亂套了。”

STM老頭兒說:“不錯,想得挺深,你說的這些操作,我把他們叫做副作用,不能重復執行,不能放到atomic代碼塊中讓STM管理。換句話說atomic中的代碼應該是冪等的。如果違背了這一點,后果自負!”

小強心中一凜:“這是程序員要操心的事情了,不管我倆的事情, 不過即使如此,他們的代碼也極度地簡化了,只需要用個atomic,就能實現安全地并發,實在是太爽了。”

旺財說道:“你說得天花亂墜,這STM有什么缺點?”

老頭兒說:“天下沒有免費的午餐,很容易想到STM的局限性, 如果對于同一個數據,并發寫入很多的時候,沖突就大大增加了,不斷地重復執行,效率很低。所以更適合寫入少,讀取多的場景。”

“好吧,我們這就執行這個轉賬操作,有問題就找你!”

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

 

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

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

2021-11-23 23:13:11

數據庫安全工具

2019-02-12 09:45:27

2018-06-14 10:20:20

2009-06-18 16:54:11

Fedora 11910

2010-09-17 10:45:04

李彥宏

2019-06-27 17:30:46

貝銳科技網絡傳輸

2022-06-02 07:36:14

5G5G商用

2017-10-11 09:04:16

服務器劫難死機

2015-06-02 16:16:56

GoogleAndroid M

2016-08-02 11:03:22

數字 系列

2016-09-13 15:24:24

孟憲坤 思維

2018-06-05 15:41:22

進程線程協程

2010-08-20 09:02:57

菲律賓總統互聯網

2020-11-16 17:50:21

華為北京聯通5G

2013-07-24 10:24:55

蘋果iPhone財報

2014-01-17 17:20:18

昆騰數據保護大數據管理

2014-05-04 14:15:31

2022-04-26 15:17:52

AI數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美黄页 | 91看片网址| 北条麻妃视频在线观看 | 欧美日韩亚洲在线 | 黑人一级黄色大片 | 日韩一区二区三区av | 久久精品色欧美aⅴ一区二区 | 久久99精品久久久久久国产越南 | 久久最新精品 | 中文在线观看视频 | 精品视频一区二区 | 精品国产99 | 99热国产在线播放 | 成人在线观看免费爱爱 | 亚洲福利| 日韩视频在线免费观看 | 欧美日韩成人在线 | 欧美久久一区二区三区 | 国产精品一区二区久久 | 精品久久久一区二区 | 亚洲天堂一区二区 | 久久精品一区二 | 日韩成人一区 | 成年免费大片黄在线观看一级 | 精品久久久久一区二区国产 | 九九九视频在线观看 | 农村妇女毛片精品久久久 | 亚洲日韩中文字幕一区 | 国产日韩精品视频 | 欧美精品久久久久 | 亚洲国产成人av好男人在线观看 | 草草视频在线播放 | 国产成人综合在线 | 三级黄色网址 | 国产三级在线观看播放 | 天天天堂| 综合亚洲视频 | 精品国产欧美一区二区三区成人 | 国产色婷婷久久99精品91 | 国产一区二区免费 | 亚洲精品免费在线观看 |