ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本
public class TestThreadLocal {
ThreadLocal<String> myLocal = new ThreadLocal<String>();
String myName;
public String getName() {
return myName;
}
public void setName(String name) {
myName = name;
}
public static void main(String[] args) throws InterruptedException {
TestThreadLocal ooo = new TestThreadLocal();
Thread[] threadArray = new Thread[10];
for (int i = 0; i < 10; i++) {
Thread thi = new Thread(new ThreadWithoutThreadLocal(ooo), "thread" + i);
threadArray[i] = thi;
}
for (Thread th : threadArray) {
th.start();
}
Thread.sleep(3000);
System.out.println("-----------------------------------------------------------------");
for (int i = 0; i < 10; i++) {
Thread thi = new Thread(new ThreadWithThreadLocal(ooo), "thread" + i);
threadArray[i] = thi;
}
for (Thread th : threadArray) {
th.start();
}
}
}
class ThreadWithoutThreadLocal implements Runnable {
public TestThreadLocal ooo;
public ThreadWithoutThreadLocal(TestThreadLocal o) {
ooo = o;
}
@Override
public void run() {
String localName = Thread.currentThread().getName();
ooo.setName(localName);
ooo.myLocal.set(localName);
// it will be mess up if multi thread running
// result like this
// ThreadName =======thread1 but it's actual name thread1
// ThreadName =======thread2 but it's actual name thread2
// ThreadName =======thread1 but it's actual name thread0
// ThreadName =======thread4 but it's actual name thread4
// ThreadName =======thread3 but it's actual name thread3
// ThreadName =======thread7 but it's actual name thread7
// ThreadName =======thread6 but it's actual name thread6
// ThreadName =======thread5 but it's actual name thread5
// ThreadName =======thread8 but it's actual name thread8
// ThreadName =======thread9 but it's actual name thread9
System.out.println(
"ThreadName =======" + ooo.getName() + " but it's actual name " + Thread.currentThread().getName());
}
}
class ThreadWithThreadLocal implements Runnable {
public TestThreadLocal ooo;
public ThreadWithThreadLocal(TestThreadLocal o) {
ooo = o;
}
@Override
public void run() {
String localName = Thread.currentThread().getName();
ooo.myLocal.set(Thread.currentThread().getName());
// ThreadName======thread0 but it's actual name thread0
// ThreadName======thread2 but it's actual name thread2
// ThreadName======thread1 but it's actual name thread1
// ThreadName======thread3 but it's actual name thread3
// ThreadName======thread5 but it's actual name thread5
// ThreadName======thread4 but it's actual name thread4
// ThreadName======thread8 but it's actual name thread8
// ThreadName======thread6 but it's actual name thread6
// ThreadName======thread9 but it's actual name thread9
// ThreadName======thread7 but it's actual name thread7
System.out.println("ThreadName======" + ooo.myLocal.get() + " but it's actual name " + localName);
}
}