程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java多線程之ThreadLocal

Java多線程之ThreadLocal

編輯:關於JAVA
ThreadLOCA

l的核心思想很簡單:為每個獨立的線程提供一個變量的副本。

Java提供的synchronized關鍵字使用了“同步鎖”的機制來阻止線程的競爭訪問,即“以時間換空間”。: " 10pt; FONT-SIZE:> ThreadLocal則使用了“拷貝副本”的方式,人人有份,你用你的,我用我的,大家互不影響,是“以空間換時間”。每個線程修改變量時,實際上修改的是變量的副本,不怕影響到其它線程。

為了加深對ThreadLocal的理解,下面我使用一個例子來演示ThreadLocal如何隔離線程間的變量訪問和修改:

【1】SerialNum類

package example.thread.threadLocal;

public class SerialNum {

private static int nextSerialNum = 1;

@SuppressWarnings("unchecked")

private static ThreadLocal serialNum = new ThreadLocal() {

protected synchronized Object initialValue() {

return new Integer(nextSerialNum++);

}

};

public static int get() {

return ((Integer) (serialNum.get())).intValue();

}

@SuppressWarnings("unchecked")

public static void set(Integer newSerial){

serialNum.set(newSerial);

}

}

【2】GetSerialNumThread

package example.thread.threadLocal;

public class GetSerialNumThread implements Runnable {

public static void main(String args[]) {

GetSerialNumThread serialNumGetter = new GetSerialNumThread();

Thread t1 = new Thread(serialNumGetter, "Thread A");

Thread t2 = new Thread(serialNumGetter, "Thread B");

t1.start();

try {

t1.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

t2.start();

}

public void run() {

int mySerialNum = getSerialNum();

System.out.println("線程 " + Thread.currentThread().getName()

+ " 獲取到的序列號是" + mySerialNum);

System.out.println("線程 " + Thread.currentThread().getName()

+ " 修改了序列號為" + (mySerialNum * 3));

setSerialNum(mySerialNum * 3);

System.out.println("線程 " + Thread.currentThread().getName()

+ " 再次獲得的序列號是" + getSerialNum());

}

private int getSerialNum() {

return SerialNum.get();

}

private void setSerialNum(int newSerialNum) {

SerialNum.set(new Integer(newSerialNum));

}

}

運行的結果如下:

線程 Thread A 獲取到的序列號是1

線程 Thread A 修改了序列號為3

線程 Thread A 再次獲得的序列號是3

線程 Thread B 獲取到的序列號是2

線程 Thread B 修改了序列號為6

線程 Thread B 再次獲得的序列號是6

可見第一個線程在調用SerialNum.set(int)方法修改static變量時,其實修改的是它自己的副本,而不是修改本地變量,第二個線程在初始化的時候拿到的序列號是2而不是7。

為什麼會這樣呢?明明serialNum是靜態變量啊?其實我們只需要看看ThreadLocal的內部構造就知道了:

A. ThreadLocal的get()方法:

/**

* Returns the value in the current thread's copy of this thread-local

* variable. Creates and initializes the copy if this is the first time

* the thread has called this method.

*

* @return the current thread's value of this thread-local

*/

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

return (T)map.get(this);

// Maps are constructed lazily. if the map for this thread

// doesn't exist, create it, with this ThreadLocal and its

// initial value as its only entry.

T value = initialValue();

createMap(t, value);

return value;

}

B. ThreadLocal的set()方法:

/**

* Sets the current thread's copy of this thread-local variable

* to the specifIEd value. Many applications will have no need for

* this functionality, relying solely on the {@link #initialValue}

* method to set the values of thread-locals.

*

* @param value the value to be stored in the current threads' copy of

* this thread-local.

*/

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

可以看到ThreadLocal在內部維護了一個Map,將變量的值和線程綁定起來,get/set方法都是對該線程對應的value進行操作,所以不會影響到其它線程。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved