ThreadLocal是Java爲線程安全提供的工具類,它代表一個線程局部變量,通過把數據放到ThreadLocal中可以讓線程創建一個該變量的副本,從而避免併發訪問的線程安全問題。
下面是對該類的使用:
class Account
{
/* 定義一個ThreadLocal類型的變量,該變量將是一個線程局部變量
每個線程都會保留該變量的一個副本 */
private ThreadLocal<String> name = new ThreadLocal<>();
// 定義一個初始化name成員變量的構造器
public Account(String str)
{
this.name.set(str);
// 下面代碼用於訪問當前線程的name副本的值
System.out.println("---" + this.name.get());
}
// name的setter和getter方法
public String getName()
{
return name.get();
}
public void setName(String str)
{
this.name.set(str);
}
}
class MyTest extends Thread
{
// 定義一個Account類型的成員變量
private Account account;
public MyTest(Account account, String name)
{
super(name);
this.account = account;
}
public void run()
{
// 循環10次
for (int i = 0 ; i < 10 ; i++)
{
// 當i == 6時輸出將賬戶名替換成當前線程名
if (i == 6)
{
account.setName(getName());
}
// 輸出同一個賬戶的賬戶名和循環變量
System.out.println(account.getName()
+ " 賬戶的i值:" + i);
}
}
}
public class ThreadLocalTest
{
public static void main(String[] args)
{
// 啓動兩條線程,兩條線程共享同一個Account
Account at = new Account("初始名");
/*
雖然兩條線程共享同一個賬戶,即只有一個賬戶名
但由於賬戶名是ThreadLocal類型的,所以每條線程
都完全擁有各自的賬戶名副本,所以從i == 6之後,將看到兩條
線程訪問同一個賬戶時看到不同的賬戶名。
*/
new MyTest(at , "線程甲").start();
new MyTest(at , "線程乙").start ();
}
}
運行上面代碼會發現三個線程之間互不干擾,每個線程都完全擁有自己的ThreadLocal變量。ThreadLocal和其他所有的同步機制一樣,是爲了解決多線程中對同一變量的訪問衝突,解決了多線程的併發訪問,單並不能代替同步機制,兩者面對的問題領域不同。同步機制是爲了同步多個線程對相同資源的併發訪問,先多個線程之間進行通訊的有效方式;而ThreadLocal是爲了隔離多個線程的數據共享,避免線程之間對共享資源的進程,不存在線程同步的問題。