类ThreadLocal的使用
主要解决的是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程私有数据。
类ThreadLocal解决的是变量在不同线程间的隔离线,也就是不同线程拥有自己的值,不同线程中的值是可以放入ThreadLocal类中进行保存的
方法get()与null
package Third; public class Run { public static ThreadLocal tl = new ThreadLocal(); public static void main(String[] args) { if (tl.get() == null) { System.out.println("从未放过值"); tl.set("我的值"); } System.out.println(tl.get()); System.out.println(tl.get()); } }
验证线程变量的隔离性
package Third; public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 100; i++) { if (Tools.tl.get() == null) { Tools.tl.set("ThreadA" + (i + 1)); } else { System.out.println("ThreadA get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadB extends Thread { @Override public void run() { try { for (int i = 0; i < 100; i++) { if (Tools.tl.get() == null) { Tools.tl.set("ThreadB" + (i + 1)); } else { System.out.println("ThreadB get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Tools { public static ThreadLocal tl = new ThreadLocal(); }
package Third; 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++) { if (Tools.tl.get() == null) { Tools.tl.set("Main" + (i + 1)); } else { System.out.println("Main get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
每个线程取出自己的数据
package Third; import java.util.Date; public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 20; i++) { if (Tools.tl.get() == null) { Tools.tl.set(new Date()); } System.out.println("A " + Tools.tl.get().getTime()); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Third; import java.util.Date; public class ThreadB extends Thread { @Override public void run() { try { for (int i = 0; i < 20; i++) { if (Tools.tl.get() == null) { Tools.tl.set(new Date()); } System.out.println("B " + Tools.tl.get().getTime()); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Third; import java.util.Date; public class Tools { public static ThreadLocal<Date> tl = new ThreadLocal<Date>(); }
package Third; public class Run { public static void main(String[] args) { try { ThreadA a = new ThreadA(); a.start(); Thread.sleep(1000); ThreadB b = new ThreadB(); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
怎么实现第一次调用get()不返回null呢?也就是具有默认值的效果
解决get()返回null问题
package Third; public class ThreadLocalExt extends ThreadLocal { @Override protected Object initialValue() { return "我是默认值 第一次get不再为null"; } }
package Third; public class Run { public static ThreadLocalExt tl = new ThreadLocalExt(); public static void main(String[] args) { if (tl.get() == null) { System.out.println("从未放过值"); tl.set("我的值"); } System.out.println(tl.get()); System.out.println(tl.get()); } }
此案例仅仅证明main线程有自己的值,那其他线程呢?
再次验证线程变量的隔离性
package Third; public class Tools { public static ThreadLocalExt tl = new ThreadLocalExt(); }
package Third; import java.util.Date; public class ThreadLocalExt extends ThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); } }
package Third; public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { System.out.println("在ThreadA线程中取值=" + Tools.tl.get()); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Third; public class Run { public static void main(String[] args) { try { for (int i = 0; i < 10; i++) { System.out.println(" 在Main线程中取值=" + Tools.tl.get()); Thread.sleep(100); } Thread.sleep(5000); ThreadA a = new ThreadA(); a.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }