Java線程範圍變量——ThreadLocal的模擬和解釋
一、測試代碼
public class XY_ThreadData
{
private static Integer data = 0;
private static Map<Thread, Integer> map = new HashMap<Thread, Integer>();
private static ThreadLocal<Integer> local = new ThreadLocal<Integer>();
public static void setData(Integer value)
{
data = value;
}
public static Integer getData()
{
System.out.println("ThreadName:" + Thread.currentThread() + " data value:" + data);
return data;
}
public static void setMapData(Integer value)
{
map.put(Thread.currentThread(), value);
}
public static Integer getMapData()
{
Object obj = map.get(Thread.currentThread());
System.out.println("ThreadName:" + Thread.currentThread() + "map value:" + obj);
return Integer.parseInt(obj.toString());
}
public static void setThreadLocalData(Integer value)
{
local.set(value);
}
public static Integer getThreadLocalData()
{
Object obj = local.get();
System.out.println("ThreadName:" + Thread.currentThread() + "threadlocal value:" + obj);
return Integer.parseInt(obj.toString());
}
}
public class XY_ThreadData_Test
{
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
new Thread(new Runnable() {
public void run()
{
final int value = new Random().nextInt(); // 每個線程自己創建的變量
XY_ThreadData.setData(value);
XY_ThreadData.getData();
}
}).start();
}
}
}
ThreadName:Thread[Thread-3,5,main] data value:1046062244
ThreadName:Thread[Thread-6,5,main] data value:-879673875
ThreadName:Thread[Thread-2,5,main] data value:-125397465
ThreadName:Thread[Thread-4,5,main] data value:-1546413071
ThreadName:Thread[Thread-0,5,main] data value:754770101
ThreadName:Thread[Thread-8,5,main] data value:-1666786926
ThreadName:Thread[Thread-5,5,main] data value:-1666786926
ThreadName:Thread[Thread-9,5,main] data value:1046062244
ThreadName:Thread[Thread-1,5,main] data value:269410746
ThreadName:Thread[Thread-7,5,main] data value:269410746
分析:可以看到以下兩個線程中data的值時一樣的,沒有做到各個線程變量獨一份
ThreadName:Thread[Thread-8,5,main] data value:-1666786926
ThreadName:Thread[Thread-5,5,main] data value:-1666786926
public class XY_ThreadData_Test
{
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
new Thread(new Runnable() {
public void run()
{
final int value = new Random().nextInt();
XY_ThreadData.setMapData(value);
XY_ThreadData.getMapData();
}
}).start();
}
}
}
ThreadName:Thread[Thread-0,5,main]map value:-1138167111
ThreadName:Thread[Thread-4,5,main]map value:-1545929782
ThreadName:Thread[Thread-6,5,main]map value:-1612385717
ThreadName:Thread[Thread-3,5,main]map value:-1390594683
ThreadName:Thread[Thread-8,5,main]map value:518506934
ThreadName:Thread[Thread-2,5,main]map value:1583239372
ThreadName:Thread[Thread-5,5,main]map value:995578601
ThreadName:Thread[Thread-1,5,main]map value:-916627474
ThreadName:Thread[Thread-7,5,main]map value:-960206804
ThreadName:Thread[Thread-9,5,main]map value:-1187504747
分析:模擬線程變量獨一份,無重複
public class XY_ThreadData_Test
{
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
new Thread(new Runnable() {
public void run()
{
final int value = new Random().nextInt();
XY_ThreadData.setThreadLocalData(value);
XY_ThreadData.getThreadLocalData();
}
}).start();
}
}
}
ThreadName:Thread[Thread-1,5,main]threadlocal value:935024745
ThreadName:Thread[Thread-4,5,main]threadlocal value:1207176846
ThreadName:Thread[Thread-7,5,main]threadlocal value:-1503260374
ThreadName:Thread[Thread-9,5,main]threadlocal value:-1538563684
ThreadName:Thread[Thread-6,5,main]threadlocal value:955259906
ThreadName:Thread[Thread-8,5,main]threadlocal value:894428541
ThreadName:Thread[Thread-3,5,main]threadlocal value:730986356
ThreadName:Thread[Thread-2,5,main]threadlocal value:-540225655
ThreadName:Thread[Thread-5,5,main]threadlocal value:-2003809947
ThreadName:Thread[Thread-0,5,main]threadlocal value:1917431015
分析:線程變量獨一份,無重複
二、ThreadLocal分析
要點1
ThreadLocal不是用來解決共享對象的多線程訪問問題的,一般情況下通過ThreadLocal.set()到線程中的對象是該線程自己使用的對象,其他線程是不需要訪問的,也訪問不到的。各個線程中訪問的是不同的對象。
要點2
說ThreadLocal使得各線程能夠保持各自獨立的一個對象,並不是通過ThreadLocal.set()來實現的,而是通過每個線程中的new對象的操作來創建的對象,每個線程創建一個,不是什麼對象的拷貝或副本。通ThreadLocal.set()將這個新創建的對象的引用保存到各線程的自己的一個map中,每個線程都有這樣一個map,執行ThreadLocal.get()時,各線程從自己的map中取出放進去的對象,因此取出來的是各自自己線程中的對象,ThreadLocal實例是作為map的key來使用的。
要點3
如果ThreadLocal.set()進去的東西本來就是多個線程共享的同一個對象,那麼多個線程的ThreadLocal.get()取得的還是這個共享對象本身,還是有並發訪問問題。
更多關於ThreadLocal信息請參看:https://www.iteye.com/topic/103804
最後更新:2017-04-03 16:48:59