ThreadLocal
先看不使用ThreadLocal的例子:
package ch1.base.threadlocal;
public class NoThreadLocal {
static Integer count = new Integer(1);
public static class TestTask implements Runnable{
int id;
public TestTask(int id){
this.id =id;
}
public void run(){
System.out.println(Thread.currentThread().getName()+":start");
count = count+1;
System.out.println(Thread.currentThread().getName()+":"+count);
}
}
//运行三个线程
public void StartThreadArray(){
Thread[] runs = new Thread[3];
for(int i=0;i<runs.length;i++){
runs[i] = new Thread(new TestTask(i));
}
for(int i=0;i<runs.length;i++){
runs[i].start();
}
}
public static void main(String[] args) {
NoThreadLocal noThreadLocal = new NoThreadLocal();
noThreadLocal.StartThreadArray();
}
}
/*
输出:
Thread-1:start
Thread-0:start
Thread-0:3
Thread-2:start
Thread-1:2
Thread-2:4
Process finished with exit code 0
*/
再来看使用ThreadLocal的例子
package ch1.base.threadlocal;
//演示ThreadLocal的使用
public class UseThreadLocal {
private static ThreadLocal<Integer> intLocal = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
private static ThreadLocal<String> stringThreadLocal;
//测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
public static class TestThread implements Runnable{
int id;
public TestThread(int id){
this.id = id;
}
public void run(){
System.out.println(Thread.currentThread().getName()+": start");
Integer s = intLocal.get();
s=s+id;
intLocal.set(s);
System.out.println(Thread.currentThread().getName()+":"+intLocal.get());
// intLocal.remove();
}
}
//运行三个线程
public void runThreadThree(){
Thread[] runs = new Thread[3];
for(int i=0;i<runs.length;i++){
runs[i] = new Thread(new TestThread(i));
}
for(int i=0;i<runs.length;i++){
runs[i].start();
}
}
public static void main(String[] args) {
UseThreadLocal test = new UseThreadLocal();
test.runThreadThree();
}
}
/*
Thread-0: start
Thread-1: start
Thread-2: start
Thread-0:1
Thread-1:2
Thread-2:3
Process finished with exit code 0
*/
基础
ThreadLocal是一个关于创建线程局部变量的类。
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。
有一个误区是ThreadLocal的目的是为了解决多线程访问资源时的共享问题 但ThreadLocal 并不解决多线程 共享 变量的问题。既然变量不共享,那就更谈不上同步的问题。
理解
ThreadLoal 变量,它的基本原理是,同一个 ThreadLocal 所包含的对象(对ThreadLocal< String >而言即为 String 类型变量),在不同的 Thread 中有不同的副本(实际是不同的实例)。这里有几点需要注意
因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来
既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题
既无共享,何来同步问题,又何来解决同步问题一说?
那 ThreadLocal 到底解决了什么问题,又适用于什么样的场景?
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
核心意思是
ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。
总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。这让我想到了Js中的一个特性:闭包.闭包下的所有变量都是只属于自己的,而ThreadLocal就是只属于线程自己的对象. 另外,该场景下,并非必须使用 ThreadLocal ,其它方式完全可以实现同样的效果,只是 ThreadLocal 使得实现更简洁。
参考:https://blog.csdn.net/qq_30054997/article/details/81515668