日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ThreadLocal可以解决并发问题吗

發(fā)布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ThreadLocal可以解决并发问题吗 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

到底什么是線程的不安全?為什么會存在線程的不安全?線程的不安全其實就是多個線程并發(fā)的去操作同一共享變量沒用做同步所產生意料之外的結果。那是如何體現出來的呢?我們看下面的一個非常經典的例子:兩個操作員同時操作同一個銀行賬戶,A操作員存錢,100B操作員取錢50。我們看一下流程。

兩個操作員同時處理,沒用做同步這個時候我們發(fā)現銀行賬戶最終余額剩余950元,在我們想的最終結果銀行賬戶應該剩余1000+100-50=1050元,在執(zhí)行過程中我們沒有加鎖,最終導致了運行結果偏離預期。那么如何解決的?一般的解決措施就是加鎖,加同步鎖所以這就需要使用者一定要知道鎖是什么。我們來看一下加鎖之后的效果是不是我們所預期的。

在添加同步鎖后我們可以看到,A操作員和B操作員同時去操作賬戶,但是A先搶占到資源,所以B就只能等待A操作員釋放鎖才能去操作銀行賬戶,那么最終結果是我們所預期的嗎?答案是的。

同步的話一般都是加鎖,如果現在我想創(chuàng)建多個線程每個線程都是訪問的自己的變量呢?各個線程之間毫無關聯?

答案是有的。

ThreadLocal問題

ThreadLocal是JDK提供的,它提供了線程本地變量。什么是線程本地變量呢?其實就是你創(chuàng)建了一個Threadlocal變量,每個訪問Threadlocal變量的線程都有一個本地副本。我們看下面的圖:

從上面看出你創(chuàng)建一個ThreadLocal變量,每個訪問該的線程都會復制到自己的本地,所以線程操作的都是本地的副本,這也就是說每個線程都是操作的自己本地的變量,那就完美的避免了線程安全的問題。

在這里還有一個問題。我在寫這篇文章的時候看過很多文章,總的來說就是ThreadLocal就是為了解決多線程并發(fā)問題而提供的一種方法,還有一種解釋就是ThreadLocal的最終目的就是為了解決多線程訪問共享資源所產生的。真的對嗎?ThreadLocal并沒有共享那么從何而來的同步呢?

自己的想法

在看了Java并發(fā)編程之美后我所理解的Threadlocal提供了線程本地變量的副本,每個線程實際操作的是自己本地的變量副本,也就是說該變量副本只能當前線程訪問,就不存在多個線程共享的問題,從Threadlocal名字我們也能看出本地線程。那那那它也就不存在去解決并發(fā)問題了。

如何使用

我們來看下面的例子。

輸出結果:

Thread[Thread-1,5,main]====57
Thread[Thread-0,5,main]====75

創(chuàng)建了兩個線程,它們都在threadlocal上面都set了一個隨機數,我們看最后的輸出結果每個都是不同的值,那么我們如果把threadlocal替換成一個集合會發(fā)生什么,由于兩個線程時上個線程生成的隨機數57會被第二個線程覆蓋掉,而在Threadlocal中兩個線程都是操作的自己的本地副本,那么兩個線程互不影響都無法操控到對方的數據,因此它們存取的都是不同的值。

實現原理

那么Threadlocal是如何實現的呢?在研究Threadlocal的實現原理我們先看一下Thread的內部屬性。

  • threadLocals 此線程保存的Threadlocal的值

inheritableThreadLocals等到后面再說。

在Thread的內部屬性中我們看到了這兩個默認為null的屬性,threadLocals用來保存Threadlocal的本地副本,默認是為null只有調用Threadlocal的set時才會創(chuàng)建。也就是說Threadlocal就類似一個工具,它的作用就是把value的值通過set存在線程每個線程的threadLocals 中,只要線程一直存在threadLocals 也就一直存在。所以當不需要使用本地變量的時候可以調用Threadlocal的remove來清空本地變量。而threadLocals 為什么繼承于ThreadLocalMap呢?ThreadLocalMap是一個定制的HashMap,而使用Map的原因就是可以每個線程關聯多個Threadlocal變量。

set方法

我們來看一下set方法是如何實現的。

可以看出流程非常簡單,首先獲取當前線程然后在進行下一步操作,我們在看一下getMap做了什么

getMap主要就是返回了當前threadLocals的屬性。那如果map為空呢?

如果map為空的話就直接創(chuàng)建一個新的ThreadLocalMap。

我們來看一下流程圖。

get方法

看一下Get方法

首先根據當前線程獲取實例如果存在就返回,如果不存在就先初始化一個空值,然后判斷如果當前threadLoacals不為空就直接set一個空,否則就創(chuàng)建一個變量。

remove方法

remove方法相對來說比較簡單。

總結

Threadlocal的實現原理其實就是通過set把value set到線程的threadlocals屬性中,threadlocals類型是Map其中的Key就是Threadlocal的this引用,value就是我們所set的值,如果當前線程不銷毀的話threadlocals會一直存在。一直存在的話可能會造成內存溢出,所以使用完之后盡量remove一下。不過在這里又有一個問題那就是如果我的線程想要讀取主線程的變量要怎么做?我們上面的例子都是設置的新創(chuàng)建的線程,那么現在我在主線程中set一個值,這個時候我在新創(chuàng)建的線程中可以讀取到嗎?答案是不可以,因為Threadlocal不支持繼承性。

我們看下面的例子:

輸出結果:

Thread[Thread-0,5,main]====null

也就是說Threadlocal不支持繼承性,主線程設置了值,在子線程中是獲取不到的。那我現在想要獲取主線程里面的值要怎么做?

Threadlocal是實現不了的,不過Threadlocal有一個子類可以實現。InheritableThreadLocal,InheritableThreadLocal是Threadlocal的實現,我們來看一個簡單的例子。

輸出結果:

Thread[Thread-0,5,main]====1000

運行結果發(fā)現子線程是可以獲取到主線程設置的值的,那它是如何實現的?

我們看一下代碼實現:

InheritableThreadLocal是繼承Threadlocal的,并且把threadlocals給替換成inheritableThreadLocals了所以上面的inheritableThreadLocals我要留在最后說,那么替換成inheritableThreadLocals后子線程就可以獲取到主線程設置的屬性了嗎?我們在看一下Thread的實現。

看Thread的初始化方法可以看出,先獲取了當前線程(主線程)判斷主線程的inheritableThreadLocals不為空的話就調用createInheritedMap方法賦值給子線程中的inheritableThreadLocals。具體不在這里解釋太多。有機會在寫一篇文章來解釋。

總結

以上是生活随笔為你收集整理的ThreadLocal可以解决并发问题吗的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。