亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java線程變量ThreadLocal詳細解讀

 更新時間:2024年01月18日 09:31:56   作者:小白不很白  
這篇文章主要介紹了Java線程變量ThreadLocal詳細解讀,多線程訪問同一個變量的時候,很容易出現(xiàn)問題,特別是多線程對一個共享變量進行寫入的時候,為了線程的安全在進行數(shù)據(jù)寫入時候會進行數(shù)據(jù)的同步,需要的朋友可以參考下

Java線程變量ThreadLocal

多線程訪問同一個變量的時候,很容易出現(xiàn)問題,特別是多線程對一個共享變量進行寫入的時候。為了線程的安全在進行數(shù)據(jù)寫入時候會進行數(shù)據(jù)的同步。

在這里插入圖片描述

如上圖: 如果要想實現(xiàn)多個線程操作同一個數(shù)據(jù)而不被其他線程所影響,就必須加鎖操作,加鎖又增加了使用的復(fù)雜度。

ThredLocal的用處就是當多個線程操作同一個變量的時候可以在創(chuàng)建一個ThredLocal,把共享變量復(fù)制到線程的本地threadLocals(threadLocals是Thread的成員變量) 中,這樣各個線程進行操作的時候只能操作自己本地數(shù)據(jù),這樣就不會存儲在線程不安全的問題了。

下面舉個例子:

public class ThreadLocalTest {
    // 創(chuàng)建一個ThreadLocal
    static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    static Integer num = 5;
        public static void main(String[] args) throws InterruptedException {
                new Thread(()->{
                    // 線程1 把num 同步到threadLocal中
                    threadLocal.set(num);
                    // 線程1 獲取threadLocal中的數(shù)據(jù)
                    System.out.println("線程1: " + threadLocal.get());
                }).start();
                new Thread(()->{
                    // 線程2 獲取threadLocal中的數(shù)據(jù)
                    System.out.println("線程2: "+ threadLocal.get());
                }).start();
            System.out.println("主線程: " + threadLocal.get());
        }
}

結(jié)果:由上面的返回可以知道,當在線程1設(shè)置了設(shè)置了數(shù)據(jù)時在線程2是訪問不到的**,主線程**也訪問不到。

ThreadLocal的實現(xiàn)原理

由下圖可知 Thread類中有一個成員變量 ThreadLocal.ThreadLocalMap **threadLocals **= **null ** 是ThreadLocalMap類型的,本地變量都是存儲在ThreadLocalMap中的,ThreadLocal只是一個外殼。ThreadLocalMap是ThreadLocal中的內(nèi)部類,是一個定制化的Map形式,那就代表一個線程可以有多個ThreadLocal本地變量。key就是ThreadLocal本身,value就是存儲的本地變量。

在這里插入圖片描述

1.set()

 public void set(T value) {
      // 獲取當前線程
      Thread t = Thread.currentThread();
     // 獲取線程的成員變量threadLocals
      ThreadLocalMap map = getMap(t);
      if (map != null)
          // ThreadLoacl 對象為key  同步的變量為value
          map.set(this, value);
      else
          // 如果是第一次 則創(chuàng)建ThreadLocalMap 并且賦值
            createMap(t, value);
  }
// 獲取線程的成員變量threadLocals
ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
}
// 第一次創(chuàng)建ThreadLocalMap(this, firstValue)
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
}

2.get()

public T get() {
    // 獲取當前線程
    Thread t = Thread.currentThread();
    // 獲取線程的成員變量threadLocals
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 獲取hashMap的值
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 如果為null
    return setInitialValue();
}
 private T setInitialValue() {
  // 初始化值為null
  T value = initialValue();
     // 獲取當前線程
  Thread t = Thread.currentThread();
   // 獲取當前線程的threadLocals 成員變量
  ThreadLocalMap map = getMap(t);
   // 如果數(shù)據(jù)為null則會存儲把這個ThreadLocal的對象在這個線程的值存儲為null
  if (map != null)
      map.set(this, value);
  else
      createMap(t, value);
  return value;
}
//初始化值
protected T initialValue() {
    return null;
}

3. remove()

public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

ThreadLocal不具備繼承性

從上面的set接口 和 get接口就不難看出我們現(xiàn)在存儲、獲取、刪除數(shù)據(jù)都是在當前線程threadLocals成員變量中存儲的。所以父線程和存儲的數(shù)據(jù)在子線程中獲取不了,在子線程中存儲的數(shù)據(jù)在父線程中存儲不了。

例:

public class ThreadLocalTest {
    static ThreadLocal<Integer> stringThreadLocal = new ThreadLocal<>();
    static Integer num = 5;
        public static void main(String[] args) throws InterruptedException {
                new Thread(()->{
                    stringThreadLocal.set(num);
                    System.out.println("線程1: " + stringThreadLocal.get());
                    new Thread(()->{
                        System.out.println("線程1的子線程: " + stringThreadLocal.get());
                    }).start();
                }).start();
        }
}

結(jié)果:

在這里插入圖片描述

InheritableThreadLocal類

為了解決上述問題,為了讓子類能夠訪問父類的數(shù)據(jù),則InheritableThreadLocal應(yīng)用而生。

首先InheritableThreadLocal類繼承了ThreadLocal類 并重寫了ThreadLocla的三個方法

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    // 只返回父類線程的值
    protected T childValue(T parentValue) {
        return parentValue;
    }
    // 獲取線程inheritableThreadLocals值
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
    // 創(chuàng)建當前線程的inheritableThreadLocals
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

再看下Thread創(chuàng)建的init方法

  private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
     ......
       // 獲取父類線程
        Thread parent = currentThread();
     ........
       // 如果 在創(chuàng)建子類線程的時候如果返現(xiàn)父類線程的數(shù)據(jù)不為null 則把父類線程的數(shù)據(jù)存儲到子類線程的
         //inheritableThreadLocals成員變量中去
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    }

這樣父類線程的inheritThreadLocals數(shù)據(jù)就存儲到了子類變量中去了。 值得注意的事,雖然能用父類的放進去的值,但是不影響父類的操作,也就是子類和父類的值是隔離開的。

package com.example.spring;


public class ThreadLocalTest {

    static ThreadLocal<Integer> stringThreadLocal = new ThreadLocal<>();
    static InheritableThreadLocal<Integer> integerInheritableThreadLocal = new InheritableThreadLocal();

    static Integer num = 5;

        public static void main(String[] args) throws InterruptedException {

                new Thread(()->{
                    integerInheritableThreadLocal.set(num);
                    System.out.println("線程1: " + integerInheritableThreadLocal.get());
                    new Thread(()->{
                        integerInheritableThreadLocal.set(4);
                        System.out.println("線程1的子線程: " + integerInheritableThreadLocal.get());
                    }).start();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程1的最終結(jié)果:" + integerInheritableThreadLocal.get());
                }).start();
        }
}

在這里插入圖片描述

到此這篇關(guān)于Java線程變量ThreadLocal詳細解讀的文章就介紹到這了,更多相關(guān)Java線程變量ThreadLocal內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java線程死鎖實例及解決方法

    Java線程死鎖實例及解決方法

    這篇文章主要介紹了Java線程死鎖實例及解決方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • MyBatis中的JdbcType映射使用詳解

    MyBatis中的JdbcType映射使用詳解

    這篇文章主要介紹了MyBatis中的JdbcType映射使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 通過Java實現(xiàn)添加或刪除PDF中的附件

    通過Java實現(xiàn)添加或刪除PDF中的附件

    當我們在制作PDF文件或者PPT演示文稿的時候,為了讓自己的文件更全面詳細,就會在文件中添加附件。本文為大家整理了Java實現(xiàn)添加或刪除PDF中的附件的方法,需要的可以參考下
    2023-01-01
  • java制作簡單的坦克大戰(zhàn)

    java制作簡單的坦克大戰(zhàn)

    坦克大戰(zhàn)是我們小時候玩紅白機時代的經(jīng)典游戲,看到有不少小伙伴都使用各種語言實現(xiàn)了一下,手癢癢,也使用java做的一個比較簡單的坦克大戰(zhàn),主要面向于學(xué)過Java的人群,與學(xué)了一段時間的人,有利于面向?qū)ο笏枷氲奶岣?,推薦給大家。
    2015-03-03
  • Automapper實現(xiàn)自動映射的實例代碼

    Automapper實現(xiàn)自動映射的實例代碼

    這篇文章主要介紹了Automapper實現(xiàn)自動映射的實例代碼,需要的朋友可以參考下
    2017-09-09
  • idea中項目文件目錄消失如何解決

    idea中項目文件目錄消失如何解決

    這篇文章主要介紹了idea中項目文件目錄消失的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • springboot自定義Starter過程解析

    springboot自定義Starter過程解析

    這篇文章主要介紹了springboot自定義Starter過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Java Mybatis框架增刪查改與核心配置詳解流程與用法

    Java Mybatis框架增刪查改與核心配置詳解流程與用法

    MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO為數(shù)據(jù)庫中的記錄
    2021-10-10
  • java實現(xiàn)二維數(shù)組轉(zhuǎn)json的方法示例

    java實現(xiàn)二維數(shù)組轉(zhuǎn)json的方法示例

    這篇文章主要介紹了java實現(xiàn)二維數(shù)組轉(zhuǎn)json的方法,涉及java數(shù)組遍歷及json格式數(shù)據(jù)構(gòu)造相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • Java求質(zhì)數(shù)的幾種常用算法分析

    Java求質(zhì)數(shù)的幾種常用算法分析

    這篇文章主要介紹了Java求質(zhì)數(shù)的幾種常用算法,結(jié)合實例形式分析了三種比較常見的求質(zhì)數(shù)算法原理及相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2018-12-12

最新評論