目录
1、什么是ThreadLocal?
ThreadLocal是一种变量类型,称为“局部变量类型”。一般用private static修饰。
2、为什么要用ThreadLocal?
提供线程间的数据隔离效果。
我们知道多线程面临着种种问题,其实最根本的就是因为线程之间的共享数据没有正确处理。
一旦我们在多线程中声明一个全局变量,那么他就是线程共享的,势必需要考虑多线程问题。于是就有了ThreadLocal,他是线程私有的变量,即一个可以声明为全局变量,却是线程私有的变量,不需要考虑变量共享的问题
3、ThreadLocal的内部实现?
ThreadLocal的内部实现是通过一个ThreadLocalMap实现的。ThreadLocalMap是Thread的变量。ThreadLocalMap的key可以简单的理解为当前线程,value就是你设置的值。
通过源码可以知道,ThreadLocal的set方式的实现逻辑是:先通过Thread.currentThread()获取当前线程,在通过getMap(t)得到当前线程的ThreadLocalMap,把set(T value)方法的values设置到当前线程的ThreadLocalMap的value值。
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's 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);
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
4、怎么用ThreadLocal?
- ThreadLocal提供了一种途径,让你可以设置一个全局的线程隔离的数据,每个线程都可以往ThreadLocal里面塞值,不用担心线程共享的问题。
- 另外ThreadLocal有一个妙用,可以保证一个方法,对于每个线程只执行一次
- 线程隔离的共享变量
package threadTest;
public class ThreadLocalTest {
static ThreadLocal<String> localVar = new ThreadLocal<>();
static void print(String str) {
//打印当前线程中本地内存中本地变量的值
System.out.println(str + " :" + localVar.get());
//清除本地内存中的本地变量
localVar.remove();
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
localVar.set("localVar1");
//调用打印方法
print("thread1");
//打印本地变量
System.out.println("after remove : " + localVar.get());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
localVar.set("localVar2");
//调用打印方法
print("thread2");
//打印本地变量
System.out.println("after remove : " + localVar.get());
}
});
t1.start();
t2.start();
localVar.set("locals");
print("主线程:" + localVar.get());
}
}
- 每个线程只执行一次
package threadTest;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadLocalTest2 {
private static ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();
private static ThreadLocal<Boolean> threadLocal1 = new ThreadLocal<>();//多个ThreadLocal是隔离的
public static void main(String[] args) {
// 新建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 往线程池中提交任务
Future future = executorService.submit(() -> {
threadLocal.set(false);
for (int i = 0; i < 5; i++) {
System.out.println(threadLocal.get());
System.out.println(threadLocal1.get());//多个ThreadLocal是隔离的,输出null
System.out.println(i);
justInvokOnce();
}
});
// 分析任务结果
try {
if (future.get() == null) {//如果Future's get返回null,任务完成
System.out.println("任务完成");
}
} catch (InterruptedException | ExecutionException e) {
System.out.println(e);
}
// 关闭线程池
executorService.shutdown();
}
public static void justInvokOnce() {
if (!threadLocal.get()) { // 因为threadLocal是线程私有的,同一个线程最多只执行一次
System.out.println("仅执行一次");
threadLocal.set(true);
}
}
}
更多内容请关注微信公众号“外里科技”
官方公众号 | 外里科技 |
运营公众号 | 英雄赚 |
微信 | wxid_8awklmbh1fzm22 |
1247408032 | |
开源代码 | https://gitee.com/B_T/beimi |