標籤:web new 串連 實現 nbsp com 視窗 火車站 local
在上文中,《Java代碼品質改進之:同步對象的選擇》,我們提出了一個情境:火車站有3個售票視窗,同時在售一趟列車的100個座位。我們通過鎖定一個靠譜的同步對象,完成了上面的功能。
現在,讓我們反過來,每個視窗負責一趟車。比如一號視窗就賣1號列車的票,二號視窗就賣2號列車的票。不過它們需要同時開始賣票。
一:ThreadLocal的最簡應用
首先,既然是各賣各的火車了,那麼,就不需要同步了。於是代碼又迴歸到:
但是當前的代碼肯定是不對的,每個線程訪問的都是同一個火車的ticket,並且還會出現超售現象。要保證每new一個視窗出來,就有一趟自己的列車,我們就可以用到ThreadLocal對象了。
讓我們首先替換掉ticket變數,改為:
然後,售票的代碼改為:
雖然ticket依然是一個static變數,但是,運行程式你會發現,新起一個線程,不同的線程還是會擁有自己的ticket,不會互相干擾。也就是實現了每個視窗賣自己那趟車的目標。
二:ThreadLocal VS 執行個體變數
每一個程式員都應該是杠精。為什麼,因為回過神來的我們發現,只要回到第一段代碼中,把ticket中的static去掉,就能達到同樣的目的:
試下上面的代碼,是不是也能達到各賣各的目的?
我們是腦袋被門板擠了,才想出來一個TheadLocal這樣的複雜方案嗎?
如果單純說上面的這段代碼,是的。但是,還有很多的場合,是ThreadLocal的用武之處。比如,我們並不永遠使用extends Thead的方式來寫多線程,我們還可能用implements Runnable的方式來寫多線程(ps:還有更多的寫法哦),如下:
而在這種情況下,我們就不得不使用TheadLocal了,這裡就不放出代碼了,大家可以試一下。
甚至,更進一步的,我們是不是能夠把ticket這個變數放進方法內部呢,如果放入方法
內部的話,我們同樣也是必須要使用ThreadLocal才能達到實現目的,如下:
總之,簡單來說:當要啟動並執行代碼本身不是很方便訪問當前的線程執行個體的時候,就是ThreadLocal的用武之地。
三:ThreadLocal的應用情境
ThreadLocal有這樣一些應用情境,比如串連池管理、會話管理等等。
在串連池的管理中,當我們需要擷取一個串連,就應該為每一次擷取給出不同的串連。在web應用中,請求是被線程池管理的,也就是說擷取串連這個行為不是單線程行為,所以我們最好就要設計成不同的線程不能擷取同一個串連,要保證能做到這樣,就應該使用ThreadLocal了。
可能有人會表示,那不能設計成執行個體變數嗎?答案是:不能。因為,在web應用中,線程都不是被我們自己管理的,所以,最佳的做法就是使用ThreadLocal。一個標準的做法如下:
最後作為補充,我們再來看看hibernate中ThreadLocal的應用:
以下是廣告時間:最課程(http://zuikc.com)正在招收Java就業班學員,如果你想學習更多的Java高品質代碼編寫方面的技巧,請聯絡我們哦。
Java代碼品質改進之:使用ThreadLocal維護線程內部變數