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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

ThreadLocal相关

發布時間:2024/4/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ThreadLocal相关 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/lufeng20/article/details/24314381

?

ThreadLocal是什么

  早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多線程程序。

  當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。

  從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。

  所以,在Java中編寫線程局部變量的代碼相對來說要笨拙一些,因此造成線程局部變量沒有在Java開發者中得到很好的普及。

ThreadLocal的接口方法

ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:

  • void set(Object value)設置當前線程的線程局部變量的值。
  • public Object get()該方法返回當前線程所對應的線程局部變量。
  • public void remove()將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快內存回收的速度。
  • protected Object initialValue()返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,并且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。

  值得一提的是,在JDK5.0中,ThreadLocal已經支持泛型,該類的類名已經變為ThreadLocal<T>。API方法也相應進行了調整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。

  ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用于存儲每一個線程的變量副本,Map中元素的鍵為線程對象,而值對應線程的變量副本。我們自己就可以提供一個簡單的實現版本:

?

[java]?view plaincopy print?
  • package?com.test;??
  • ??
  • public?class?TestNum?{??
  • ????//?①通過匿名內部類覆蓋ThreadLocal的initialValue()方法,指定初始值??
  • ????private?static?ThreadLocal<Integer>?seqNum?=?new?ThreadLocal<Integer>()?{??
  • ????????public?Integer?initialValue()?{??
  • ????????????return?0;??
  • ????????}??
  • ????};??
  • ??
  • ????//?②獲取下一個序列值??
  • ????public?int?getNextNum()?{??
  • ????????seqNum.set(seqNum.get()?+?1);??
  • ????????return?seqNum.get();??
  • ????}??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????TestNum?sn?=?new?TestNum();??
  • ????????//?③?3個線程共享sn,各自產生序列號??
  • ????????TestClient?t1?=?new?TestClient(sn);??
  • ????????TestClient?t2?=?new?TestClient(sn);??
  • ????????TestClient?t3?=?new?TestClient(sn);??
  • ????????t1.start();??
  • ????????t2.start();??
  • ????????t3.start();??
  • ????}??
  • ??
  • ????private?static?class?TestClient?extends?Thread?{??
  • ????????private?TestNum?sn;??
  • ??
  • ????????public?TestClient(TestNum?sn)?{??
  • ????????????this.sn?=?sn;??
  • ????????}??
  • ??
  • ????????public?void?run()?{??
  • ????????????for?(int?i?=?0;?i?<?3;?i++)?{??
  • ????????????????//?④每個線程打出3個序列值??
  • ????????????????System.out.println("thread["?+?Thread.currentThread().getName()?+?"]?-->?sn["??
  • ?????????????????????????+?sn.getNextNum()?+?"]");??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??


  • ?

    ?通常我們通過匿名內部類的方式定義ThreadLocal的子類,提供初始的變量值,如例子中①處所示。TestClient線程產生一組序列號,在③處,我們生成3個TestClient,它們共享同一個TestNum實例。運行以上代碼,在控制臺上輸出以下的結果:

    ?

    thread[Thread-0] --> sn[1]
    thread[Thread-1] --> sn[1]
    thread[Thread-2] --> sn[1]
    thread[Thread-1] --> sn[2]
    thread[Thread-0] --> sn[2]
    thread[Thread-1] --> sn[3]
    thread[Thread-2] --> sn[2]
    thread[Thread-0] --> sn[3]
    thread[Thread-2] --> sn[3]

    ?

    考察輸出的結果信息,我們發現每個線程所產生的序號雖然都共享同一個TestNum實例,但它們并沒有發生相互干擾的情況,而是各自產生獨立的序列號,這是因為我們通過ThreadLocal為每一個線程提供了單獨的副本。

    ?

    Thread同步機制的比較

      ThreadLocal和線程同步機制相比有什么優勢呢?ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。

      在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候對變量進行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。

      而ThreadLocal則從另一個角度來解決多線程的并發訪問。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

      由于ThreadLocal中可以持有任何類型的對象,低版本JDK所提供的get()返回的是Object對象,需要強制類型轉換。但JDK 5.0通過泛型很好的解決了這個問題,在一定程度地簡化ThreadLocal的使用,代碼清單 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。

      概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

      spring使用ThreadLocal解決線程安全問題我們知道在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因為Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態采用ThreadLocal進行處理,讓它們也成為線程安全的狀態,因為有狀態的Bean就可以在多線程中共享了。

    轉載于:https://www.cnblogs.com/lycroseup/p/7221923.html

    總結

    以上是生活随笔為你收集整理的ThreadLocal相关的全部內容,希望文章能夠幫你解決所遇到的問題。

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