最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ThreadLocal簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2017年08月04日 10:20:32   作者:huangyong  
這篇文章主要為大家詳細(xì)介紹了ThreadLocal簡(jiǎn)介的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

ThreadLocal,直譯為“線程本地”或“本地線程”,如果你真的這么認(rèn)為,那就錯(cuò)了!其實(shí),它就是一個(gè)容器,用于存放線程的局部變量,我認(rèn)為應(yīng)該叫做 ThreadLocalVariable(線程局部變量)才對(duì),真不理解為什么當(dāng)初 Sun 公司的工程師這樣命名。
早在 JDK 1.2 的時(shí)代,java.lang.ThreadLocal 就誕生了,它是為了解決多線程并發(fā)問題而設(shè)計(jì)的,只不過設(shè)計(jì)得有些難用,所以至

今沒有得到廣泛使用。其實(shí)它還是挺有用的,不相信的話,我們一起來看看這個(gè)例子吧。

一個(gè)序列號(hào)生成器的程序,可能同時(shí)會(huì)有多個(gè)線程并發(fā)訪問它,要保證每個(gè)線程得到的序列號(hào)都是自增的,而不能相互干擾。

先定義一個(gè)接口:

public interface Sequence {

 int getNumber();
}

每次調(diào)用 getNumber() 方法可獲取一個(gè)序列號(hào),下次再調(diào)用時(shí),序列號(hào)會(huì)自增。
再做一個(gè)線程類:

public class ClientThread extends Thread {

 private Sequence sequence;

 public ClientThread(Sequence sequence) {
  this.sequence = sequence;
 }

 @Override
 public void run() {
  for (int i = 0; i < 3; i++) {
   System.out.println(Thread.currentThread().getName() + " => " + sequence.getNumber());
  }
 }
}

在線程中連續(xù)輸出三次線程名與其對(duì)應(yīng)的序列號(hào)。
我們先不用 ThreadLocal,來做一個(gè)實(shí)現(xiàn)類吧。

public class SequenceA implements Sequence {

 private static int number = 0;

 public int getNumber() {
  number = number + 1;
  return number;
 }

 public static void main(String[] args) {
  Sequence sequence = new SequenceA();

  ClientThread thread1 = new ClientThread(sequence);
  ClientThread thread2 = new ClientThread(sequence);
  ClientThread thread3 = new ClientThread(sequence);

  thread1.start();
  thread2.start();
  thread3.start();
 }
}

序列號(hào)初始值是0,在 main() 方法中模擬了三個(gè)線程,運(yùn)行后結(jié)果如下:
Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
Thread-2 => 4
Thread-2 => 5
Thread-2 => 6
Thread-1 => 7
Thread-1 => 8
Thread-1 => 9

由于線程啟動(dòng)順序是隨機(jī)的,所以并不是0、1、2這樣的順序,這個(gè)好理解。為什么當(dāng) Thread-0 輸出了1、2、3之后,而 Thread-2 卻輸出了4、5、6呢?線程之間竟然共享了 static 變量!這就是所謂的“非線程安全”問題了。

那么如何來保證“線程安全”呢?對(duì)應(yīng)于這個(gè)案例,就是說不同的線程可擁有自己的 static 變量,如何實(shí)現(xiàn)呢?下面看看另外一個(gè)實(shí)現(xiàn)吧。

public class SequenceB implements Sequence {

 private static ThreadLocal<Integer> numberContainer = new ThreadLocal<Integer>() {
  @Override
  protected Integer initialValue() {
   return 0;
  }
 };

 public int getNumber() {
  numberContainer.set(numberContainer.get() + 1);
  return numberContainer.get();
 }

 public static void main(String[] args) {
  Sequence sequence = new SequenceB();

  ClientThread thread1 = new ClientThread(sequence);
  ClientThread thread2 = new ClientThread(sequence);
  ClientThread thread3 = new ClientThread(sequence);

  thread1.start();
  thread2.start();
  thread3.start();
 }
}

通過 ThreadLocal 封裝了一個(gè) Integer 類型的 numberContainer 靜態(tài)成員變量,并且初始值是0。再看 getNumber() 方法,首先從 numberContainer 中 get 出當(dāng)前的值,加1,隨后 set 到 numberContainer 中,最后將 numberContainer 中 get 出當(dāng)前的值并返回。

是不是很惡心?但是很強(qiáng)大!確實(shí)稍微饒了一下,我們不妨把 ThreadLocal 看成是一個(gè)容器,這樣理解就簡(jiǎn)單了。所以,這里故意用 Container 這個(gè)單詞作為后綴來命名 ThreadLocal 變量。

運(yùn)行結(jié)果如何呢?看看吧。

Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
Thread-2 => 1
Thread-2 => 2
Thread-2 => 3
Thread-1 => 1
Thread-1 => 2
Thread-1 => 3

每個(gè)線程相互獨(dú)立了,同樣是 static 變量,對(duì)于不同的線程而言,它沒有被共享,而是每個(gè)線程各一份,這樣也就保證了線程安全。 也就是說,TheadLocal 為每一個(gè)線程提供了一個(gè)獨(dú)立的副本!

搞清楚 ThreadLocal 的原理之后,有必要總結(jié)一下 ThreadLocal 的 API,其實(shí)很簡(jiǎn)單。
1.public void set(T value):將值放入線程局部變量中
2.public T get():從線程局部變量中獲取值
3.public void remove():從線程局部變量中移除值(有助于 JVM 垃圾回收)
4.protected T initialValue():返回線程局部變量中的初始值(默認(rèn)為 null) 

為什么 initialValue() 方法是 protected 的呢?就是為了提醒程序員們,這個(gè)方法是要你們來實(shí)現(xiàn)的,請(qǐng)給這個(gè)線程局部變量一個(gè)初始值吧。

了解了原理與這些 API,其實(shí)想想 ThreadLocal 里面不就是封裝了一個(gè) Map 嗎?自己都可以寫一個(gè) ThreadLocal 了,嘗試一下吧。

public class MyThreadLocal<T> {

 private Map<Thread, T> container = Collections.synchronizedMap(new HashMap<Thread, T>());

 public void set(T value) {
  container.put(Thread.currentThread(), value);
 }

 public T get() {
  Thread thread = Thread.currentThread();
  T value = container.get(thread);
  if (value == null && !container.containsKey(thread)) {
   value = initialValue();
   container.put(thread, value);
  }
  return value;
 }

 public void remove() {
  container.remove(Thread.currentThread());
 }

 protected T initialValue() {
  return null;
 }
}

以上完全山寨了一個(gè) ThreadLocal,其中中定義了一個(gè)同步 Map(為什么要這樣?請(qǐng)讀者自行思考),代碼應(yīng)該非常容易讀懂。
下面用這 MyThreadLocal 再來實(shí)現(xiàn)一把看看。

public class SequenceC implements Sequence {

 private static MyThreadLocal<Integer> numberContainer = new MyThreadLocal<Integer>() {
  @Override
  protected Integer initialValue() {
   return 0;
  }
 };

 public int getNumber() {
  numberContainer.set(numberContainer.get() + 1);
  return numberContainer.get();
 }

 public static void main(String[] args) {
  Sequence sequence = new SequenceC();

  ClientThread thread1 = new ClientThread(sequence);
  ClientThread thread2 = new ClientThread(sequence);
  ClientThread thread3 = new ClientThread(sequence);

  thread1.start();
  thread2.start();
  thread3.start();
 }
}

以上代碼其實(shí)就是將 ThreadLocal 替換成了 MyThreadLocal,僅此而已,運(yùn)行效果和之前的一樣,也是正確的。
其實(shí) ThreadLocal 可以單獨(dú)成為一種設(shè)計(jì)模式,就看你怎么看了。 

ThreadLocal 具體有哪些使用案例呢?通過 ThreadLocal 存放 JDBC Connection,以達(dá)到事務(wù)控制的能力。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中如何獲取當(dāng)前服務(wù)器的IP地址

    Java中如何獲取當(dāng)前服務(wù)器的IP地址

    這篇文章主要給大家介紹了關(guān)于Java中如何獲取當(dāng)前服務(wù)器的IP地址的相關(guān)資料,我們可以使用Java中的InetAddress類來獲取Linux服務(wù)器的IP地址,需要的朋友可以參考下
    2023-07-07
  • java使用回溯法求解數(shù)獨(dú)示例

    java使用回溯法求解數(shù)獨(dú)示例

    這篇文章主要介紹了java使用回溯法求解數(shù)獨(dú)示例,大家參考使用吧
    2014-01-01
  • 如何使用BufferedReader循環(huán)讀文件

    如何使用BufferedReader循環(huán)讀文件

    這篇文章主要介紹了如何使用BufferedReader循環(huán)讀文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot生成和操作PDF的代碼詳解

    SpringBoot生成和操作PDF的代碼詳解

    本文主要介紹了在SpringBoot項(xiàng)目下,通過代碼和操作步驟,詳細(xì)的介紹了如何操作PDF,希望可以幫助到準(zhǔn)備通過JAVA操作PDF的你,項(xiàng)目框架用的SpringBoot,但在JAVA中代碼都是通用的,需要的朋友可以參考下
    2025-01-01
  • JAVA中excel導(dǎo)出一對(duì)多合并具體實(shí)現(xiàn)

    JAVA中excel導(dǎo)出一對(duì)多合并具體實(shí)現(xiàn)

    項(xiàng)目中經(jīng)常會(huì)使用到導(dǎo)出功能,有導(dǎo)出Word,有導(dǎo)出Excel的,下面這篇文章主要給大家介紹了關(guān)于JAVA中excel導(dǎo)出一對(duì)多合并具體實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • Java反射使用的詳細(xì)介紹(最新推薦)

    Java反射使用的詳細(xì)介紹(最新推薦)

    這篇文章主要介紹了Java反射使用的詳細(xì)介紹,反射的第一步都是先得到編譯后的Class類對(duì)象,然后就可以得到Class的全部成分,本文結(jié)合實(shí)例代碼詳細(xì)講解,需要的朋友可以參考下
    2023-02-02
  • mybatis plus使用redis作為二級(jí)緩存的方法

    mybatis plus使用redis作為二級(jí)緩存的方法

    這篇文章主要介紹了mybatis plus使用redis作為二級(jí)緩存的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java多線程之定時(shí)器Timer的實(shí)現(xiàn)

    Java多線程之定時(shí)器Timer的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Java多線程中定時(shí)器Timer類的使用以及模擬實(shí)現(xiàn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Java根據(jù)表達(dá)式獲取對(duì)象中的值及設(shè)置值的例子

    Java根據(jù)表達(dá)式獲取對(duì)象中的值及設(shè)置值的例子

    這篇文章主要介紹了Java根據(jù)表達(dá)式獲取對(duì)象中的值及設(shè)置值的例子,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-03-03
  • java高級(jí)用法之JNA中的回調(diào)問題

    java高級(jí)用法之JNA中的回調(diào)問題

    這篇文章主要介紹了java高級(jí)用法之:JNA中的回調(diào),為了方便和native方法進(jìn)行交互,JNA中同樣提供了Callback用來進(jìn)行回調(diào),JNA中回調(diào)的本質(zhì)是一個(gè)指向native函數(shù)的指針,通過這個(gè)指針可以調(diào)用native函數(shù)中的方法,一起來看看吧
    2022-05-05

最新評(píng)論

九江县| 阿尔山市| 宜宾市| 政和县| 洞头县| 杭锦旗| 大名县| 扎赉特旗| 长汀县| 石楼县| 平遥县| 张家口市| 介休市| 卢龙县| 古浪县| 台州市| 吉首市| 万荣县| 千阳县| 公安县| 庐江县| 漳平市| 铜川市| 威海市| 曲周县| 彰武县| 大渡口区| 蓬安县| 镇康县| 广德县| 龙陵县| 民县| 惠州市| 延吉市| 太保市| 兖州市| 新巴尔虎右旗| 绥芬河市| 阿鲁科尔沁旗| 简阳市| 西和县|