关于变量值的共享,我们首先会想到public static形式变量,这种形式的变量,所有的线程都可以访问、使用该变量。如果每个线程都有自己的共享变量该如何实现?ThreadLocal类正是为了解决这个问题的。
1.ThreadLocal-隔离性
ThreadLocal类可以为每个线程绑定自己的值,在每个线程中,以私有数据形式存在。可通过set()与get()方法操作,下面验证ThreadLocal变量的隔离性
public class ThreadLocalTest {
static ThreadLocal threadLocal = new ThreadLocal();
public static void main(String[] args) {
Thread threadA = new Thread(){
@Override
public void run() {
for (int i = 0; i < 5; i++) {
threadLocal.set("ThreadA:"+(i+1));
System.out.println(threadLocal.get());
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Thread threadB = new Thread(){
@Override
public void run() {
for (int i = 0; i < 5; i++) {
threadLocal.set("ThreadB:"+(i+1));
System.out.println(threadLocal.get());
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
threadA.start();
threadB.start();
for (int i = 0; i < 5; i++) {
threadLocal.set("Main Thread"+(i+1));
System.out.println(threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出结果为
Main Thread1
ThreadB:1
ThreadA:1
ThreadA:2
ThreadB:2
Main Thread2
ThreadA:3
ThreadB:3
Main Thread3
Main Thread4
ThreadA:4
ThreadB:4
ThreadB:5
Main Thread5
ThreadA:5
可以看到不同的线程对应保存不同的值,验证了ThreadLocal变量在不同线程中的隔离性。
2.ThreadLocal get()方法默认值初始化
通过上面的例子你可能很好奇,如果不调用set() 预先设定值,直接调用get()方法会返回什么呢?
public class ThreadLocalMethod {
static ThreadLocal threadLocal = new ThreadLocal();
public static void main(String[] args) {
if(threadLocal.get() == null){
System.out.println("默认值为null");
threadLocal.set("设置的值");
}
System.out.println(threadLocal.get());
}
}
输出结果为
默认值为null
设置的值
从中可看出,默认值为null,那么设置并初始化默认值呢?
public class ThreadLocalInit {
static InitedThreadLocal threadLocal = new InitedThreadLocal();
public static void main(String[] args) {
if(threadLocal.get() == null){
System.out.println("默认值为null");
threadLocal.set("设置的值");
}
System.out.println(threadLocal.get());
}
public static class InitedThreadLocal extends ThreadLocal{
@Override
protected Object initialValue() {
return "第一次get的默认值";
}
}
}
输出结果为:
第一次get的默认值
3.InheritableThreadLocal类的使用
public class InheritableTest {
static Inheritable inheritable = new Inheritable();
public static void main(String[] args) {
Thread threadA = new Thread(){
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("ThreadA线程中的取值:"+inheritable.get());
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
};
threadA.start();
for (int i = 0; i < 3; i++) {
System.out.println("Main线程中的取值:"+inheritable.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static class Inheritable extends InheritableThreadLocal{
@Override
protected Object initialValue() {
return new Date().getTime();
}
}
}
输出为:
Main线程中的取值:1505115923423
ThreadA线程中的取值:1505115923423
ThreadA线程中的取值:1505115923423
Main线程中的取值:1505115923423
Main线程中的取值:1505115923423
ThreadA线程中的取值:1505115923423
可以看出使用InheritableThradLocal类,可以让子线程从父线程那取得值。