实现变量值的共享,可以使用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中的值发生变化,那么子线程取得的还是旧值