一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java多線程編程之ThreadLocal線程范圍內的共享變量

Java多線程編程之ThreadLocal線程范圍內的共享變量

2019-12-18 16:50junjie JAVA教程

這篇文章主要介紹了Java多線程編程之ThreadLocal線程范圍內的共享變量,本文講解了ThreadLocal的作用和目的、ThreadLocal的應用場景、ThreadLocal的使用實例等,需要的朋友可以參考下

模擬ThreadLocal類實現:線程范圍內的共享變量,每個線程只能訪問他自己的,不能訪問別的線程。

Java多線程編程之ThreadLocal線程范圍內的共享變量

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.ljq.test.thread;
 
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
 
/**
 * 線程范圍內的共享變量
 *
 * 三個模塊共享數據,主線程模塊和AB模塊
 *
 * @author Administrator
 *
 */
public class ThreadScopeShareData {
  // 準備共享的數據
  private static int data = 0;
  // 存放各個線程對應的數據
  private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
 
  public static void main(String[] args) {
    // 啟動兩個線程
    for (int i = 0; i < 2; i++) {
      new Thread(new Runnable() {
        @Override
        public void run() {
          // 現在當前線程中修改一下數據,給出修改信息
          int data = new Random().nextInt();
          // 將線程信息和對應數據存儲起來
          threadData.put(Thread.currentThread(), data);
          System.out.println(Thread.currentThread().getName() + " has put data :" + data);
          new A().get();
          new B().get();
        }
      }).start();
    }
  }
 
  static class A {
    public void get() {
      int data = threadData.get(Thread.currentThread());
      System.out.println("A from " + Thread.currentThread().getName()
          + " get data :" + data);
    }
  }
 
  static class B {
    public void get() {
      int data = threadData.get(Thread.currentThread());
      System.out.println("B from " + Thread.currentThread().getName()
          + " get data :" + data);
    }
  }
}

 

運行結果:

Java多線程編程之ThreadLocal線程范圍內的共享變量

ThreadLocal的作用和目的:
用于實現線程內的數據共享,即對于相同的程序代碼,多個模塊在同一個線程中運行時要共享一份數據,而在另外線程中運行時又共享另外一份數據。

每個線程調用全局ThreadLocal對象的set方法,就相當于往其內部的map中增加一條記錄,key分別是各自的線程,value是各自的set方法傳進去的值。在線程結束時可以調用ThreadLocal.clear()方法,這樣會更快釋放內存,不調用也可以,因為線程結束后也可以自動釋放相關的ThreadLocal變量。

ThreadLocal的應用場景:
訂單處理包含一系列操作:減少庫存量、增加一條流水臺賬、修改總賬,這幾個操作要在同一個事務中完成,通常也即同一個線程中進行處理,如果累加公司應收款的操作失敗了,則應該把前面的操作回滾,否則,提交所有操作,這要求這些操作使用相同的數據庫連接對象,而這些操作的代碼分別位于不同的模塊類中。

銀行轉賬包含一系列操作: 把轉出帳戶的余額減少,把轉入帳戶的余額增加,這兩個操作要在同一個事務中完成,它們必須使用相同的數據庫連接對象,轉入和轉出操作的代碼分別是兩個不同的帳戶對象的方法。

例如Strut2的ActionContext,同一段代碼被不同的線程調用運行時,該代碼操作的數據是每個線程各自的狀態和數據,對于不同的線程來說,getContext方法拿到的對象都不相同,對同一個線程來說,不管調用getContext方法多少次和在哪個模塊中getContext方法,拿到的都是同一個。

實驗案例:定義一個全局共享的ThreadLocal變量,然后啟動多個線程向該ThreadLocal變量中存儲一個隨機值,接著各個線程調用另外其他多個類的方法,這多個類的方法中讀取這個ThreadLocal變量的值,就可以看到多個類在同一個線程中共享同一份數據。

實現對ThreadLocal變量的封裝,讓外界不要直接操作ThreadLocal變量。
對基本類型的數據的封裝,這種應用相對很少見。
對對象類型的數據的封裝,比較常見,即讓某個類針對不同線程分別創建一個獨立的實例對象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package com.ljq.test.thread;
 
import java.util.Random;
 
/**
 * ThreadLocal類及應用技巧
 *
 * 將線程范圍內共享數據進行封裝,封裝到一個單獨的數據類中,提供設置獲取方法
 * 將該類單例化,提供獲取實例對象的方法,獲取到的實例對象是已經封裝好的當前線程范圍內的對象
 */
public class ThreadLocalTest {
 
  private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
  //private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
  public static void main(String[] args) {
    for(int i=0;i<2;i++){
      new Thread(new Runnable(){
        @Override
        public void run() {
          int data = new Random().nextInt();
          System.out.println(Thread.currentThread().getName() + " has put data :" + data);
          x.set(data);
           
          /*        
          MyThreadScopeData myData = new MyThreadScopeData();
          myData.setName("name" + data);
          myData.setAge(data);
          myThreadScopeData.set(myData);
          */
          MyThreadScopeData.getThreadInstance().setName("name" + data);
          MyThreadScopeData.getThreadInstance().setAge(data);
          new A().get();
          new B().get();
        }
      }).start();
    }
  }
   
  //使用獲取到的線程范圍內的對象實例調用相應方法
  static class A{
    public void get(){
      int data = x.get();
      System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data);
       
      /*    
      MyThreadScopeData myData = myThreadScopeData.get();
      System.out.println("A from " + Thread.currentThread().getName()
          + " getMyData: " + myData.getName() + "," + myData.getAge());
      */
      MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
      System.out.println("A from " + Thread.currentThread().getName()
          + " getMyData: " + myData.getName() + "," + myData.getAge());
    }
  }
   
  //使用獲取到的線程范圍內的對象實例調用相應方法
  static class B{
    public void get(){
      int data = x.get();   
      System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data);
       
      MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
      System.out.println("B from " + Thread.currentThread().getName()
          + " getMyData: " + myData.getName() + "," + myData.getAge());    
    }  
  }
}
 
 
class MyThreadScopeData {
 
  // 單例
  private MyThreadScopeData() {
  }
 
  // 提供獲取實例方法,不加synchronized關鍵字表示線程各拿各自的數據,互不干擾
  public static/* synchronized */MyThreadScopeData getThreadInstance() {
    // 從當前線程范圍內數據集中獲取實例對象
    MyThreadScopeData instance = map.get();
    if (instance == null) {
      instance = new MyThreadScopeData();
      map.set(instance);
    }
    return instance;
  }
 
  // 將實例對象存入當前線程范圍內數據集中
  private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
 
  private String name;
  private int age;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public int getAge() {
    return age;
  }
 
  public void setAge(int age) {
    this.age = age;
  }
}

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美女孩videos | 精品亚洲麻豆1区2区3区 | 黄网国产 | 男人天堂视频网 | 久久这里有精品 | 龟甲情感超市全文阅读 小说 | 国产三级精品三级男人的天堂 | 免费看片aⅴ免费大片 | 校花被拖到野外伦小说 | 亚洲精品www久久久久久久软件 | 和两个男人玩3p好爽视频 | 黄色a∨| 久久99国产精品二区不卡 | 99re在线精品视频免费 | 国产91精品在线观看 | 国产精品高清一区二区三区 | 国产精品一久久香蕉产线看 | 无颜之月全集免费观看 | 天天爱天天操天天射 | 天天天天天干 | 五月色天在线视频综合观看 | 亚洲AV福利天堂一区二区三 | 免费观看欧美成人禁片 | 午夜精品久久久久久久2023 | 国产伦精品一区二区三区女 | 高清毛片aaaaaaaaa片 | 日本在线www | 免费大秀视频在线播放 | 亚洲精选在线观看 | 精品国产自在现线拍国语 | 99re这里都是精品 | 日韩欧美国产综合精品 | 国产亚洲精品视频中文字幕 | 波多野结衣178部中文字幕 | 国产精品免费视频能看 | 欧美精品国产第一区二区 | 天堂成人在线观看 | 任我行视频在线观看国语 | 处女摘花 | 日韩丝袜在线观看 | 人人澡 人人澡碰人人看软件 |