ThreadLocal
應用場景
當我們多個線程需要對一個公共的變量就行修改,而我們希望這個變量不受其他線程的影響,但我們有不方便所線程同步(線程同步會影響性能),那麼我們可以爲每個線程都設置一個單獨的變量,讓他們自己去修改,此時,我們就可以用上ThreadLocal
- 下面,我們可以先看一下,多線程下數據同時被多個線程修改,產生的情況:
package com.zty.demo;
import java.util.ResourceBundle;
/**
* @創建人 zhangtaiyuan
* @創建時間 2020/6/23 12:49
* @描述
*/
class Channel{
private static Message message;
public static void setMessage(Message msg){
message = msg;
}
public static void send(){
System.out.println(Thread.currentThread().getName() + "[消息發送] " + message.getInfo());
}
}
class Message{
private String info;
public void setInfo(String info){
this.info = info;
}
public String getInfo() {
return info;
}
}
public class LocalDemo {
public static void main(String[] args) {
myThread("第一個線程消息","消息發送者A");
myThread("第二個線程消息","消息發送者B");
myThread("第三個線程消息","消息發送者C");
}
public static void myThread(String msgStr,String threadName){
new Thread(()->{
Message msg = new Message();
msg.setInfo(msgStr);
Channel.setMessage(msg);
Channel.send();
},threadName
).start();
}
}
輸出結果:
消息發送者A[消息發送] 第二個線程消息
消息發送者B[消息發送] 第二個線程消息
消息發送者C[消息發送] 第二個線程消息
添加上ThreadLocal:
- 此時,我們可以將Message對象放入ThreadLocal中,然後再從ThreadLocal中獲取即可,只需要修改Channel即可
class Channel{
private static final ThreadLocal<Message> local = new ThreadLocal<>(); //只是修改這個存數據這裏
public static void setMessage(Message msg){
local.set(msg);
}
public static void send(){
System.out.println(Thread.currentThread().getName() + "[消息發送] " + local.get().getInfo());
}
}
整體代碼如下:
package com.zty.demo;
import java.util.ResourceBundle;
/**
* @創建人 zhangtaiyuan
* @創建時間 2020/6/23 12:49
* @描述
*/
class Channel{
private static final ThreadLocal<Message> local = new ThreadLocal<>(); //只是修改這個存數據這裏
public static void setMessage(Message msg){
local.set(msg);
}
public static void send(){
System.out.println(Thread.currentThread().getName() + "[消息發送] " + local.get().getInfo());
}
}
class Message{
private String info;
public void setInfo(String info){
this.info = info;
}
public String getInfo() {
return info;
}
}
public class LocalDemo {
public static void main(String[] args) {
myThread("第一個線程消息","消息發送者A");
myThread("第二個線程消息","消息發送者B");
myThread("第三個線程消息","消息發送者C");
}
public static void myThread(String msgStr,String threadName){
new Thread(()->{
Message msg = new Message();
msg.setInfo(msgStr);
Channel.setMessage(msg);
Channel.send();
},threadName
).start();
}
}
原理
其實原理很簡單,在每個ThreadLocal中一個Map,Map是以"當前線程"作爲key存的值,下面是 ThreadLocal.set(T vlue);的源代碼:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}