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);
}