激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - Java多線程編程之ThreadLocal線程范圍內(nèi)的共享變量

Java多線程編程之ThreadLocal線程范圍內(nèi)的共享變量

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

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

模擬ThreadLocal類實(shí)現(xiàn):線程范圍內(nèi)的共享變量,每個(gè)線程只能訪問(wèn)他自己的,不能訪問(wèn)別的線程。

Java多線程編程之ThreadLocal線程范圍內(nèi)的共享變量

 

?
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;
 
/**
 * 線程范圍內(nèi)的共享變量
 *
 * 三個(gè)模塊共享數(shù)據(jù),主線程模塊和AB模塊
 *
 * @author Administrator
 *
 */
public class ThreadScopeShareData {
  // 準(zhǔn)備共享的數(shù)據(jù)
  private static int data = 0;
  // 存放各個(gè)線程對(duì)應(yīng)的數(shù)據(jù)
  private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
 
  public static void main(String[] args) {
    // 啟動(dòng)兩個(gè)線程
    for (int i = 0; i < 2; i++) {
      new Thread(new Runnable() {
        @Override
        public void run() {
          // 現(xiàn)在當(dāng)前線程中修改一下數(shù)據(jù),給出修改信息
          int data = new Random().nextInt();
          // 將線程信息和對(duì)應(yīng)數(shù)據(jù)存儲(chǔ)起來(lái)
          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);
    }
  }
}

 

運(yùn)行結(jié)果:

Java多線程編程之ThreadLocal線程范圍內(nèi)的共享變量

ThreadLocal的作用和目的:
用于實(shí)現(xiàn)線程內(nèi)的數(shù)據(jù)共享,即對(duì)于相同的程序代碼,多個(gè)模塊在同一個(gè)線程中運(yùn)行時(shí)要共享一份數(shù)據(jù),而在另外線程中運(yùn)行時(shí)又共享另外一份數(shù)據(jù)。

每個(gè)線程調(diào)用全局ThreadLocal對(duì)象的set方法,就相當(dāng)于往其內(nèi)部的map中增加一條記錄,key分別是各自的線程,value是各自的set方法傳進(jìn)去的值。在線程結(jié)束時(shí)可以調(diào)用ThreadLocal.clear()方法,這樣會(huì)更快釋放內(nèi)存,不調(diào)用也可以,因?yàn)榫€程結(jié)束后也可以自動(dòng)釋放相關(guān)的ThreadLocal變量。

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

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

例如Strut2的ActionContext,同一段代碼被不同的線程調(diào)用運(yùn)行時(shí),該代碼操作的數(shù)據(jù)是每個(gè)線程各自的狀態(tài)和數(shù)據(jù),對(duì)于不同的線程來(lái)說(shuō),getContext方法拿到的對(duì)象都不相同,對(duì)同一個(gè)線程來(lái)說(shuō),不管調(diào)用getContext方法多少次和在哪個(gè)模塊中g(shù)etContext方法,拿到的都是同一個(gè)。

實(shí)驗(yàn)案例:定義一個(gè)全局共享的ThreadLocal變量,然后啟動(dòng)多個(gè)線程向該ThreadLocal變量中存儲(chǔ)一個(gè)隨機(jī)值,接著各個(gè)線程調(diào)用另外其他多個(gè)類的方法,這多個(gè)類的方法中讀取這個(gè)ThreadLocal變量的值,就可以看到多個(gè)類在同一個(gè)線程中共享同一份數(shù)據(jù)。

實(shí)現(xiàn)對(duì)ThreadLocal變量的封裝,讓外界不要直接操作ThreadLocal變量。
對(duì)基本類型的數(shù)據(jù)的封裝,這種應(yīng)用相對(duì)很少見。
對(duì)對(duì)象類型的數(shù)據(jù)的封裝,比較常見,即讓某個(gè)類針對(duì)不同線程分別創(chuàng)建一個(gè)獨(dú)立的實(shí)例對(duì)象。

?
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類及應(yīng)用技巧
 *
 * 將線程范圍內(nèi)共享數(shù)據(jù)進(jìn)行封裝,封裝到一個(gè)單獨(dú)的數(shù)據(jù)類中,提供設(shè)置獲取方法
 * 將該類單例化,提供獲取實(shí)例對(duì)象的方法,獲取到的實(shí)例對(duì)象是已經(jīng)封裝好的當(dāng)前線程范圍內(nèi)的對(duì)象
 */
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();
    }
  }
   
  //使用獲取到的線程范圍內(nèi)的對(duì)象實(shí)例調(diào)用相應(yīng)方法
  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());
    }
  }
   
  //使用獲取到的線程范圍內(nèi)的對(duì)象實(shí)例調(diào)用相應(yīng)方法
  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() {
  }
 
  // 提供獲取實(shí)例方法,不加synchronized關(guān)鍵字表示線程各拿各自的數(shù)據(jù),互不干擾
  public static/* synchronized */MyThreadScopeData getThreadInstance() {
    // 從當(dāng)前線程范圍內(nèi)數(shù)據(jù)集中獲取實(shí)例對(duì)象
    MyThreadScopeData instance = map.get();
    if (instance == null) {
      instance = new MyThreadScopeData();
      map.set(instance);
    }
    return instance;
  }
 
  // 將實(shí)例對(duì)象存入當(dāng)前線程范圍內(nèi)數(shù)據(jù)集中
  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;
  }
}

 

延伸 · 閱讀

精彩推薦
  • JAVA教程Java讀取文件的簡(jiǎn)單實(shí)現(xiàn)方法

    Java讀取文件的簡(jiǎn)單實(shí)現(xiàn)方法

    這篇文章主要介紹了Java讀取文件的簡(jiǎn)單實(shí)現(xiàn)方法,通過(guò)一個(gè)讀取txt格式的log文件為例,詳細(xì)的講述了Java讀取文件的方法及原理,需要的朋友可以參考下 ...

    shichen20142672019-11-29
  • JAVA教程Java應(yīng)用服務(wù)器對(duì)比 Tomcat、Jetty、 GlassFish、WildFly

    Java應(yīng)用服務(wù)器對(duì)比 Tomcat、Jetty、 GlassFish、WildFly

    如果要編寫Java Web應(yīng)用程序,首先需要做的是做出一個(gè)困難的決定, 我們?cè)撨x擇哪種服務(wù)器來(lái)運(yùn)行Java應(yīng)用程序呢?這是一個(gè)艱難的選擇,因?yàn)槟抢镉性S多優(yōu)秀...

    今日頭條5302019-10-23
  • JAVA教程java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description

    java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description

    這篇文章主要介紹了java實(shí)現(xiàn)獲取網(wǎng)站的keywords,description的相關(guān)資料,需要的朋友可以參考下 ...

    hebedich2452019-12-13
  • JAVA教程線程安全的單例模式的幾種實(shí)現(xiàn)方法分享

    線程安全的單例模式的幾種實(shí)現(xiàn)方法分享

    線程安全的單例模式實(shí)現(xiàn)有幾種思路,個(gè)人認(rèn)為第2種方案最優(yōu)雅:、餓漢式、借助內(nèi)部類、普通加鎖解決、雙重檢測(cè),但要注意寫法,如果單體模式繼續(xù)擴(kuò)...

    java教程網(wǎng)4442019-11-07
  • JAVA教程try catch finally的執(zhí)行順序深入分析

    try catch finally的執(zhí)行順序深入分析

    首先執(zhí)行try,如果有異常執(zhí)行catch,無(wú)論如何都會(huì)執(zhí)行finally,當(dāng)有return以后,函數(shù)就會(huì)把這個(gè)數(shù)據(jù)存儲(chǔ)在某個(gè)位置,然后告訴主函數(shù),我不執(zhí)行了,接下來(lái)...

    java開發(fā)網(wǎng)4942019-10-13
  • JAVA教程自己寫的java日志類和方法代碼分享

    自己寫的java日志類和方法代碼分享

    這篇文章主要介紹了一個(gè)自己寫的java日志類和方法,下面把代碼分享給大家 ...

    java教程網(wǎng)4412019-11-04
  • JAVA教程Java中的深拷貝和淺拷貝介紹

    Java中的深拷貝和淺拷貝介紹

    對(duì)象拷貝(Object Copy)就是將一個(gè)對(duì)象的屬性拷貝到另一個(gè)有著相同類類型的對(duì)象中去。在程序中拷貝對(duì)象是很常見的,主要是為了在新的上下文環(huán)境中復(fù)用對(duì)...

    java教程網(wǎng)3432019-11-15
  • JAVA教程java中enum的用法

    java中enum的用法

    這篇文章主要介紹了java中enum的用法,包括了枚舉類型的基本定義及用法分析,對(duì)于學(xué)習(xí)Java有著一定的學(xué)習(xí)與借鑒價(jià)值,需要的朋友可以參考下 ...

    shichen20142822019-12-06
主站蜘蛛池模板: www.精品一区| 国产污污视频 | 亚洲看片网| 精品国产第一区二区三区 | 水多视频在线观看 | 99精品国产小情侣高潮露脸在线 | 激情视频导航 | 中国免费一级毛片 | 91香蕉国产亚洲一区二区三区 | 日日噜噜噜噜久久久精品毛片 | 伊人一二三四区 | 精品亚洲一 | 成人黄色免费电影 | 蜜桃视频日韩 | 女18一级大黄毛片免费女人 | 日韩美香港a一级毛片 | 免费男女乱淫真视频 | 国产99久久久久 | 日本成人午夜 | 国内精品久久久久久久久久 | 国产伦乱视频 | 污视频在线免费播放 | 成人久久久精品国产乱码一区二区 | 亚洲一级毛片 | 天天草夜夜骑 | 久久91久久久久麻豆精品 | 99视频观看 | chinese军人gay呻吟| 黄 色 免费网 站 成 人 | 亚洲成人在线视频网 | 日韩字幕 | 精品久久中文网址 | 欧美黄色片免费看 | 久啪视频 | 久久国产精品二国产精品 | 中国成人在线视频 | 国产一区精品在线观看 | 久草在线视频首页 | 国产电影av在线 | 国产高清自拍一区 | 成年人福利视频 |