ThreadLocal實現執行緒範圍內共享變數
阿新 • • 發佈:2019-02-11
1.多執行緒範圍內訪問共享物件和資料的方式。
1).如果每個執行緒要執行的程式碼一樣,可以使用同一個Runnable物件,這個Runnable物件中有共享資料,例如:買票系統。
2).每一個執行緒要執行的程式碼不一樣,這樣就需要使用多個Runnable物件了。有以下幾種方式:
(1).將需要共享的資料單獨封裝在一個物件中,建立該物件的例項逐一傳遞給Runnable物件。
(2).將需要共享的資料封裝在Runnable物件中。<span style="font-size:18px;"><span style="font-size:24px;"> final ShareData data =new ShareData(); new Thread( new Runnable(){ @Override public void run() { while(true){ data.increment(); } }}).start(); new Thread( new Runnable(){ @Override public void run() { while(true){ data.decrement(); } }}).start(); } } class ShareData{ private int j ; public synchronized void increment(){ j++; System.out.println(Thread.currentThread().getName()+ " increment "+j); } public synchronized void decrement(){ j--; System.out.println(Thread.currentThread().getName()+ " decrement "+j); } }</span></span>
<span style="font-size:18px;"><span style="font-size:24px;">class Runnable1 implements Runnable{
@Override
public void run() {
// ...
}
}
class Runnable2 implements Runnable
{
@Override
public void run() {
// ...
}
}</span></span>
(3).將Runnable物件作為某一個類的內部類, 共享資料作為這個類的外部類。
2).極端的一種方式,即在任意一個類中定義一個static變數,這將被所有執行緒共享。
2.執行緒範圍內的共享資料。
對於同一份程式程式碼,多個模組在同一個執行緒中執行時要共享一份資料,而在另外一個執行緒執行時又共享另外一份資料。
自已來做的話,也很好做。
<span style="font-size:18px;"><span style="font-size:24px;">package com.hb; import java.util.HashMap; import java.util.Map; import java.util.Random; public class ThreadLocal { private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); public static void main(String[] args) { // 建立三個執行緒,並且生產三個資料 for (int i = 0; i < 3; 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(); } } // 模組A static class A { int data = threadData.get(Thread.currentThread()); public void get() { System.out.println("A from " + Thread.currentThread().getName() + " get data " + data); } } // 模組B static class B { int data = threadData.get(Thread.currentThread()); public void get() { System.out.println("B from " + Thread.currentThread().getName() + " get data " + data); } } } </span></span>
java對這個threadData進行了封裝,ThreadLocal相當於一個Map,每一個執行緒呼叫全域性ThreadLocal物件的set方法,就相當於往其內部的map增加一條記錄。key分別是各自的執行緒。
<span style="font-size:18px;">package com.hb;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocalTest {
// private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
private final static ThreadLocal<Integer> threadData=new ThreadLocal();
public static void main(String[] args) {
// 建立三個執行緒,並且生產三個資料
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
// threadData.put(Thread.currentThread(), data);
threadData.set(data);
System.out.println(Thread.currentThread().getName()
+ " has put data " + data);
new A().get();
new B().get();
}
}).start();
}
}
// 模組A
static class A {
int data = threadData.get();//threadData.get(Thread.currentThread());
public void get() {
System.out.println("A from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
// 模組B
static class B {
int data = threadData.get();//threadData.get(Thread.currentThread());
public void get() {
System.out.println("B from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
}
</span>
值得注意的是一個ThreadLocal代表一個變數,故其中只能放一個數據。那我想放多個怎麼辦?打包唄。
l實現對ThreadLocal變數的封裝,讓外界不要直接操作ThreadLocal變數。 對基本型別的資料的封裝,這種應用相對很少見。 對物件型別的資料的封裝,比較常見,即讓某個類針對不同執行緒分別建立一個獨立的例項物件。<span style="font-size:18px;">package com.hb;
import java.util.Random;
import com.hb.ThreadLocalTest.A;
import com.hb.ThreadLocalTest.B;
public class ThreadLocalTest2 {
public static void main(String[] args) {
// 建立三個執行緒,並且生產三個資料
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
MyThreadScopeData.getThreadInstance().setName("name"+data);
MyThreadScopeData.getThreadInstance().setAge(data);
System.out.println(Thread.currentThread().getName()
+ " has put data " + data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
System.out.println("A from "+Thread.currentThread().getName()
+ " get name "+myData.getName()+", get age "+myData.getAge());
}
}
static class B{
public void get(){
MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
System.out.println("B from "+Thread.currentThread().getName()
+ " get name "+myData.getName()+", get age "+myData.getAge());
}
}
}
class MyThreadScopeData{
//將ThreadLocal封裝在此。
private MyThreadScopeData(){}
private static ThreadLocal<MyThreadScopeData> maps=new ThreadLocal<MyThreadScopeData>();
public static MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance =maps.get();
if(instance == null){
instance =new MyThreadScopeData();
maps.set(instance);
}
return instance;
}
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;
}
}
</span>