前言
路橋網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,路橋網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為路橋上1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營銷網(wǎng)站建設(shè)要多少錢,請找那個(gè)售后服務(wù)好的路橋做網(wǎng)站的公司定做!多線程的線程安全問題是微妙而且出乎意料的,因?yàn)樵跊]有進(jìn)行適當(dāng)同步的情況下多線程中各個(gè)操作的順序是不可預(yù)期的,多線程訪問同一個(gè)共享變量特別容易出現(xiàn)并發(fā)問題,特別是多個(gè)線程需要對一個(gè)共享變量進(jìn)行寫入時(shí)候,為了保證線程安全,
一般需要使用者在訪問共享變量的時(shí)候進(jìn)行適當(dāng)?shù)耐?,如下圖所示:
可以看到同步的措施一般是加鎖,這就需要使用者對鎖也要有一定了解,這顯然加重了使用者的負(fù)擔(dān)。那么有沒有一種方式當(dāng)創(chuàng)建一個(gè)變量的時(shí)候,每個(gè)線程對其進(jìn)行訪問的時(shí)候訪問的是自己線程的變量呢?其實(shí)ThreaLocal就可以做這個(gè)事情,注意一下,ThreadLocal的出現(xiàn)并不是為了解決上面的問題而出現(xiàn)的。
ThreadLocal是在JDK包里面提供的,它提供了線程本地變量,也就是如果你創(chuàng)建了一個(gè)ThreadLocal變量,那么訪問這個(gè)變量的每個(gè)線程都會有這個(gè)變量的本地拷貝,多個(gè)線程操作這個(gè)變量的時(shí)候,實(shí)際是操作自己本地內(nèi)存里面的變量,從而避免了線程安全問題,創(chuàng)建一個(gè)ThreadLocal變量后,
每個(gè)線程會拷貝一個(gè)變量到自己的本地內(nèi)存,如下圖:
好了,現(xiàn)在我們思考一個(gè)問題:ThreadLocal的實(shí)現(xiàn)原理,ThreadLocal作為變量的線程隔離方式,其內(nèi)部又是如何實(shí)現(xiàn)的呢?
首先我們要看ThreadLocal的類圖結(jié)構(gòu),如下圖所示:
如
其實(shí)每個(gè)線程的本地變量不是存到ThreadLocal實(shí)例里面的,而是存放到調(diào)用線程的threadLocals變量里面。也就是說ThreadLocal類型的本地變量是存放到具體線程內(nèi)存空間的。
ThreadLocal其實(shí)就是一個(gè)外殼,它通過set方法把value值放入調(diào)用線程threadLocals里面存放起來,當(dāng)調(diào)用線程調(diào)用它的get方法的時(shí)候再從當(dāng)前線程的threadLocals變量里面拿出來使用。如果調(diào)用線程如果一直不終止的話,那么這個(gè)本地變量會一直存放到調(diào)用線程的threadLocals變量里面,
因此,當(dāng)不需要使用本地變量時(shí)候可以通過調(diào)用ThreadLocal變量的remove方法,從當(dāng)前線程的threadLocals變量里面刪除該本地變量??赡苓€有人會問threadLocals為什么設(shè)計(jì)為Map結(jié)構(gòu)呢?很明顯是因?yàn)槊總€(gè)線程里面可以關(guān)聯(lián)多個(gè)ThreadLocal變量。
接下來我們可以進(jìn)入到ThreadLocal中的源碼如看看,如下代碼所示:
主要看set,get,remove這三個(gè)方法的實(shí)現(xiàn)邏輯,如下:
先看set(T var1)方法
public void set(T var1) { //(1)獲取當(dāng)前線程 Thread var2 = Thread.currentThread(); //(2) 當(dāng)前線程作為key,去查找對應(yīng)的線程變量,找到則設(shè)置 ThreadLocal.ThreadLocalMap var3 = this.getMap(var2); if(var3 != null) { var3.set(this, var1); } else { //(3) 第一次調(diào)用則創(chuàng)建當(dāng)前線程對應(yīng)的Hashmap this.createMap(var2, var1); } }