一,線程局部變量ThreadLocal的作用
用於實現線程內部的數據共享,既對於相同的程序代碼,多個模塊在同一個線程中運行時要共享一份數據,在另一個線程訪問的時候,訪問的由是另一份數據。
每個線程調用ThreadLocal對象的set方法時,就相當於向內部Map集合中增加一條記錄。
Map(key,value)key相當於當前的線程,value相當於set()傳遞進來的值。
ThreadLocal<T> threadLocal =new ThreadLocal<T>(); T是set()方法傳進來的值類型。
問題:一個ThreadLocal中只能存放一個變量,既其中只能存放一個數據,如果由兩個數據,可以定義兩個ThreadLocal,但是如果有多個呢?例如100個?
解決方法是定義一個對象來存放這100個數據,然后在ThreadLocal中存放這個對象。
二,在 Runnable 中創建 ThreadLocal
①、在多線程的類(如 ThreadDemo 類)中,創建一個 ThreadLocal 對象 threadXxx,用來保存線程間需要隔離處理的對象 xxx。
②、在 ThreadDemo 類中,創建一個獲取要隔離訪問的數據的方法 getXxx(),在方法中判斷,若ThreadLocal 對象為 null 時候,應該 new()一個隔離訪問類型的對象,並強制轉換為要應用的類型
③、在 ThreadDemo 類的 run()方法中,通過調用 getXxx()方法獲取要操作的數據,這樣可以保證每個線程對應一個數據對象,在任何時刻都操作的是這個對象。
代碼:
package com.itheima.gan; import java.util.Random; public class ThreadLocalTest implements Runnable{ //創建一個線程局部變量 ThreadLocal<Student> studentThreadLocal=new ThreadLocal<Student>(); @Override public void run() { //獲取當前線程的名字 String currentThreadName=Thread.currentThread().getName(); System.out.println(currentThreadName+" is running ...."); //隨機生成一個整數 Random random=new Random(); int age=random.nextInt(100); System.out.println(currentThreadName+" is set age:"+age); //通過這個方法為每一個線程都設置一個獨立的student對象 Student student=getStudent(); student.setAge(age); System.out.println(currentThreadName+" is first get age:"+student.getAge()); //線程沉睡 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } //線程第二次獲取年紀 System.out.println(currentThreadName+" is second get age:"+student.getAge()); } private Student getStudent() { //先獲取studnet對象 Student student=studentThreadLocal.get(); //判斷對象是否為空,是空的話表示沒有給局部變量設置,如果是空的話就在給局部變量重新設置一個值 if(student==null) { student=new Student(); studentThreadLocal.set(student); } return student; } public static void main(String[] args) { ThreadLocalTest test=new ThreadLocalTest(); Thread t1=new Thread(test,"線程1"); Thread t2=new Thread(test,"線程2"); t1.start(); t2.start(); } } class Student{ int age; public int getAge() { return age; } public void setAge(int age) { this.age=age; } }
運行結果: