ThreadLocal的使用

z1340954953發表於2018-04-27

ThreadLocal的作用

從上一篇對於ThreadLocal的原始碼分析,可以看出ThreadLocal不是用來將解決共享物件的多執行緒訪問問題,每個執行緒可以將執行緒的私有資料通過ThreadLocal的set方法設定到執行緒的私有的ThreadLocalMap中,其他執行緒無法訪問到。各個執行緒中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocalMap中的數值都是不同物件

ThreadLocal的使用

首先定義一個全域性共享的ThreadLocal

package com.ftf.thread.test;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadLocalPool {
	public static final ThreadLocal<String> tl = new ThreadLocal<>();
	public static void main(String[] args) {
		LocalThread t1 = new LocalThread("執行緒A");
		LocalThread t2 = new LocalThread("執行緒B");
		LocalThread t3 = new LocalThread("執行緒C");
		LocalThread t4 = new LocalThread("執行緒D");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class LocalThread extends Thread{
	private static AtomicInteger at = new AtomicInteger();
	public LocalThread(String name){
		super(name);
	}
	@Override
	public void run() {
		for(int i = 0;i<3;i++){
			ThreadLocalPool.tl.set(at.incrementAndGet()+"");
			System.out.println(Thread.currentThread().getName()+" set value :" + ThreadLocalPool.tl.get());
		}
	}
}

輸出結果:

執行緒A set value :1
執行緒D set value :4
執行緒C set value :3
執行緒B set value :2
執行緒C set value :7
執行緒D set value :6
執行緒A set value :5
執行緒D set value :10
執行緒C set value :9
執行緒B set value :8
執行緒B set value :12
執行緒A set value :11

從結果看出,每個執行緒都有自己的String,並且不會相互影響,用一個ThreadLocal也可以多次set一個資料,set僅僅表示的執行緒TheadLocal.ThreadLocalMap中table某一個位置value覆蓋,而且對於同一個ThreadLocal物件而言,set後,table絕不會多出一個資料.

給ThreadLocal設定初始值,解決get返回null的問題

public static final ThreadLocal<String> tl = new ThreadLocal<String>(){	
		protected String initialValue() {
			return "我是get時候為null時候的預設值";
		};
	};

對initialValue方法進行重寫

InheritableThreadLocal實現父執行緒向子執行緒傳遞值

package com.ftf.thread.test;

import java.util.Date;

public class InheritableTest extends InheritableThreadLocal<String> {
	@Override
	protected String initialValue() {
		return new Date().getTime()+"";
	}
	/*@Override
	protected String childValue(String parentValue) {
		return "子執行緒加上的值";
	}*/
	public static void main(String[] args) throws InterruptedException {
		Tools.it.set("我是父執行緒定義的值");
		for(int i=0;i<3;i++){
			System.out.println("Main執行緒中值:"+Tools.it.get());
			Thread.sleep(1000);
		}
		Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("子執行緒中獲取到的值"+Tools.it.get());
			}
		});
	  t.start();
	}
}
class Tools {
	public static final InheritableTest it = new InheritableTest();
}

輸出結果

Main執行緒中值:我是父執行緒定義的值
Main執行緒中值:我是父執行緒定義的值
Main執行緒中值:我是父執行緒定義的值
子執行緒中獲取到的值我是父執行緒定義的值

main執行緒是父執行緒,裡面啟動子執行緒Thread,從結果看出,子執行緒獲取到的值從父執行緒而來,而不是初始值

* 將上面的ChildValue方法放開,就能定義再次修改繼承過來的值

Main執行緒中值:我是父執行緒定義的值
Main執行緒中值:我是父執行緒定義的值
Main執行緒中值:我是父執行緒定義的值
子執行緒中獲取到的值子執行緒加上的值

ThreadLocal再總結

1. TheadLocal可以看做是一個抽屜,每個執行緒都能向裡面放資料,取資料,不會相互干擾

2. 同步和ThreadLocal是解決多執行緒中資料訪問問題的兩種思路,前者是資料共享,後者是資料隔離

3. 同步是一種時間換空間的思想,ThreadLocal是一種空間換時間的思想

4. ThreadLocal既然與執行緒相關,對於java web而言,ThreadLocal設定的是隻在一次請求中有效,是不是和request很像?因為request裡面的內容只是在一次請求中有效,對比一下兩者的區別:

* ThreadLocal只能去設定一個值,因為每次set值的時候,會找到threadLocal相同的entry,進行覆蓋

,而request每次可以設定多個值,是因為key-value的結構

參考部落格:

http://www.cnblogs.com/xrq730/p/4854820.html

《Java多執行緒核心技術》



相關文章