1. 程式人生 > >多線程學習 ThreadLocal的使用。

多線程學習 ThreadLocal的使用。

常用 私有 print gin 調用 nal 時間 end tar

  ThreadLocal ,即線程變量,是一個以ThreadLocal對象為鍵,任意對象為值得存儲接口。這個接口被附帶在線程上,也就是說一個線程可以根據一個ThreadLocal對象查詢到綁定在這個線程上的值。

  可以通過set(T)方法來設置一個值,在當前線程下,在通過get()方法獲取到原先設置的值。

  上面的文字是不是有點晦澀?來,學習一下明白的。

  變量值得共享可以使用 public static 變量的形式,所有的線程都使用同一個 public static 變量。如果想實現每一個線程都有自己的共享變量該如何解決那?

  jdk提供了ThreadLocal正是為了解決這樣的問題。  

  類ThreadLocal 主要解決的就是每個線程綁定自己的值,可以將ThreadLocal類比喻成全局存放數據的盒子,盒子中可以存儲每個線程的私有數據。

  

  下面實驗:

  1 創建ThreadLocal對象,用來存儲每個線程的私有值。

  

public class Tools {

	public static ThreadLocal t=new ThreadLocal();
}

  2 創建兩個線程A,B.

  

public class ThreadA extends Thread {

	@Override
	public void run() {
		super.run();
		try {
			for(int i=0;i<100;i++){
				Tools.t.set("ThreadA "+(i+1));
				System.out.println("ThreadA get Value " + Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  

public class ThreadB extends Thread{

	@Override
	public void run() {
		super.run();
		try {
			for(int i=0;i<100;i++){
				Tools.t.set("ThreadB "+(i+1));
				System.out.println("ThreadB get Value "+Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  主線程:

public class Run {

	public static void main(String[] args) {
		
		try {
			ThreadA a=new ThreadA();
			ThreadB b=new ThreadB();
			a.start();
			b.start();
			
			for (int i = 0; i < 100; i++) {
				Tools.t.set("main "+(i+1));
				System.out.println("main get Value "+Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

  控制臺:

ThreadB get Value ThreadB 1
ThreadA get Value ThreadA 1
main get Value main 1
ThreadA get Value ThreadA 2
main get Value main 2
ThreadB get Value ThreadB 2
main get Value main 3
ThreadA get Value ThreadA 3
ThreadB get Value ThreadB 3
ThreadA get Value ThreadA 4
ThreadB get Value ThreadB 4
main get Value main 4
ThreadB get Value ThreadB 5
ThreadA get Value ThreadA 5
main get Value main 5
main get Value main 6
ThreadB get Value ThreadB 6
ThreadA get Value ThreadA 6

  可以發現,ThreadA,ThreadB,和主線程三個在ThreadLocal中存儲的值互不影響,每個線程增加,取值,都是自己的私有的。ThreadLocal中存儲的值具有隔離性。

  使用類InheritableThreadLocal類可以讓子線程中取得父線程中的值,並修改。

  下面使用ThreadLocal來模擬統計五個線程走完一段代碼消耗的時間的問題。

  首先創建一個常用的Profiler類

  

public class Profiler {

	//第一次get()方法調用的時候會進行初始化(前提是set方法未調用),每個線程都會調用一次。
	private static final ThreadLocal<Long> TIME_THREADLOCAL=new ThreadLocal<Long>(){
		protected Long initialValue() {
			return System.currentTimeMillis();
		};
	};
	
	public static final void begin(){
		TIME_THREADLOCAL.set(System.currentTimeMillis());
	}
	
	public static final Long end(){
		return System.currentTimeMillis()-TIME_THREADLOCAL.get();
	}
}

    主線程中開啟五個線程,並調用begin()和end()方法。(關於未調用set直接調用get返回是null的情況,註釋已經解釋解決辦法。也可以通過繼承ThreadLocal類,然後重寫initialValue()方法改變初始化的值);

  

public class Run {

	public static void main(String[] args) {
		
		for (int i = 0; i < 5; i++) {
			final int temp=i;
			Thread thread=new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Profiler.begin();
						Thread.sleep(temp*1000);
						System.out.println("線程"+Thread.currentThread().getName()+"消耗時間      "+Profiler.end());
					} catch (Exception e) {
						e.printStackTrace();
					}
					
				}
			});
			thread.start();
		}
		
		
	}
}

  控制臺:

線程Thread-0消耗時間      0
線程Thread-1消耗時間      1000
線程Thread-2消耗時間      2000
線程Thread-3消耗時間      3001
線程Thread-4消耗時間      4001

  可以發現,五個線程互不影響,各自統計自己的消耗的時間。

  每一個優秀的人,都有一段沈默的時光。不抱怨,不訴苦,最後度過那段感動自己的日子。

  

多線程學習 ThreadLocal的使用。