ThreadLocal的使用

实现变量值的共享,可以使用public static变量的形式,这种形式修饰的变量在所有使用该变量的线程间都是共享的

使用ThreadLocal也可以实现变量值的共享,这种共享旨在实现每个线程自己的变量共享

 1 public class Run {
 2     public static ThreadLocal threadLocal = new ThreadLocal();
 3 
 4     public static void main(String[] args) {
 5         if (threadLocal.get() == null){
 6             System.out.println("threadLocal中没有值");
 7             threadLocal.set("testValue");
 8             threadLocal.set("testValue2");
 9         }
10         System.out.println(threadLocal.get());
11         System.out.println(threadLocal.get());
12     }
13 }
threadLocal中没有值
testValue2
testValue2

threadLocal对象在第一次调用get()方法时返回null,然后通过调用set()方法赋值,赋值以最后一次为准

本例中在main线程中执行,main线程相当于key,set的值是value

ThreadLocal解决的是多线程之间的隔离性,不同线程有自己独立的值,不同线程的值可以放在ThreadLocal中进行保存

ThreadLocal其实可以看做成全局存放数据的盒子,盒子中存放每个线程的私有数据,每个线程就是私有数据的标签


 

验证线程变量的隔离性

public class Utils {
    public static ThreadLocal threadLocal = new ThreadLocal();
}

--------------------------------------------------线程类--------------------------------------------------

public class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 100; i++) {
                Utils.threadLocal.set("ThreadA"+(i+1));
                System.out.println("ThreadA get value = "+Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
-----------------------------------------------------
public class ThreadB extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 100; i++) {
                Utils.threadLocal.set("ThreadB"+(i+1));
                System.out.println("ThreadB get value = "+Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------测试类--------------------------------------------------

public class Run {
    public static void main(String[] args) {
        try {
            ThreadA a = new ThreadA();
            ThreadB b = new ThreadB();
            a.start();
            b.start();

            for (int i = 0; i < 100; i++) {
                Utils.threadLocal.set("main"+(i+1));
                System.out.println("main get value = "+Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------console--------------------------------------------------

........
main get value = main96
ThreadA get value = ThreadA96
ThreadB get value = ThreadB96
ThreadA get value = ThreadA97
main get value = main97
ThreadB get value = ThreadB97
main get value = main98
ThreadA get value = ThreadA98
ThreadB get value = ThreadB98
ThreadA get value = ThreadA99
main get value = main99
ThreadB get value = ThreadB99
main get value = main100
ThreadA get value = ThreadA100
ThreadB get value = ThreadB100

每个线程都向threadLocal对象中set数据值,但是每个线程都可以正确的取出各自设置的值

第一次调用ThreadLocal的get方法返回的是null,如何使得第一次调用get返回不是null???使用一个继承ThreadLocal类的自定义类


 

处理ThreadLocal第一次调用get()返回null

案例1

public class MyThreadLocal extends ThreadLocal {
    @Override
    protected Object initialValue() {
        return "请先设置值,再调用get方法";
    }
}
public class Run {
    public static MyThreadLocal threadLocal = new MyThreadLocal();
    public static void main(String[] args) {
        System.out.println(threadLocal.get());
    }
}

--------------------------------------------------console--------------------------------------------------

请先设置值,再调用get方法

案例2

-----------------------------------------------------utils----------------------------------------------------

public class MyThreadLocal extends ThreadLocal {
    @Override
    protected Object initialValue() {
        return new Date().getTime();
    }
}
public class Utils {
    public static MyThreadLocal threadLocal = new MyThreadLocal();
}

--------------------------------------------------线程类--------------------------------------------------

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------测试类--------------------------------------------------

public class Run {
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("main线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            MyThread thread = new MyThread();
            thread.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------console--------------------------------------------------

main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
main线程中取值=1537495764646
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657
MyThread线程中取值=1537495770657

每个线程有自己各自的默认值


 

InheritableThreadLocal类的使用

InheritableThreadLocal类的作用是使得子线程可以继承父线程中的值

-----------------------------------------------------utils----------------------------------------------------

public class MyInheritableThreadLocal extends InheritableThreadLocal {
    @Override
    protected Object initialValue() {
        return new Date().getTime();
    }
}
-------------------------------------------------------------------------------
public class Utils {
    public static MyInheritableThreadLocal threadLocal = new MyInheritableThreadLocal();
}

--------------------------------------------------线程类--------------------------------------------------

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------测试类--------------------------------------------------

public class Run {
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println("main线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(200);
            }
            Thread.sleep(3000);
            MyThread thread = new MyThread();
            thread.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------console--------------------------------------------------

main线程中取值=1537496806863
main线程中取值=1537496806863
main线程中取值=1537496806863
main线程中取值=1537496806863
main线程中取值=1537496806863
MyThread线程中取值=1537496806863
MyThread线程中取值=1537496806863
MyThread线程中取值=1537496806863
MyThread线程中取值=1537496806863
MyThread线程中取值=1537496806863

可以发现MyThread和main中取得值是一样的,子线程继承了父线程的值

修改MyThread.java,再次测试

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                Utils.threadLocal.set(new Date().getTime());
                System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------console--------------------------------------------------

main线程中取值=1537497153735
main线程中取值=1537497153735
main线程中取值=1537497153735
main线程中取值=1537497153735
main线程中取值=1537497153735
MyThread线程中取值=1537497157740
MyThread线程中取值=1537497157940
MyThread线程中取值=1537497158140
MyThread线程中取值=1537497158341
MyThread线程中取值=1537497158542

子线程自己设置值就用自己的值,自己没设置值就会使用从父线程继承的值

子线程继承父线程的值时,可以对值做相应处理

修改MyInheritableThreadLocal.java

public class MyInheritableThreadLocal extends InheritableThreadLocal {
    @Override
    protected Object initialValue() {
        return new Date().getTime();
    }

    @Override
    protected Object childValue(Object parentValue) {
        return "从父线程继承值:"+parentValue;
    }
}

--------------------------------------------------console--------------------------------------------------

main线程中取值=1537497472137
main线程中取值=1537497472137
main线程中取值=1537497472137
main线程中取值=1537497472137
main线程中取值=1537497472137
MyThread线程中取值=从父线程继承值:1537497472137
MyThread线程中取值=从父线程继承值:1537497472137
MyThread线程中取值=从父线程继承值:1537497472137
MyThread线程中取值=从父线程继承值:1537497472137
MyThread线程中取值=从父线程继承值:1537497472137

如果子线程取值时,父线程又发生变化会怎么样呢?

修改测试类Run.java

public class Run {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            for (int i = 0; i < 5; i++) {
                Utils.threadLocal.set(new Date().getTime());
                System.out.println("main线程中取值="+ Utils.threadLocal.get());
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

--------------------------------------------------console--------------------------------------------------

main线程中取值=1537498416687
MyThread线程中取值=1537498416689
main线程中取值=1537498416889
MyThread线程中取值=1537498416689
main线程中取值=1537498417089
MyThread线程中取值=1537498416689
main线程中取值=1537498417290
MyThread线程中取值=1537498416689
main线程中取值=1537498417490
MyThread线程中取值=1537498416689

如果子线程在取值的时候父线程的InheritableThreadLocal中的值发生变化,那么子线程取得的还是旧值

posted @ 2018-09-21 10:56  *青锋*  阅读(170)  评论(0编辑  收藏  举报