关于ThreadLocal的那些事
这篇文章(看完了再看下面的)很好地解释了ThreadLocal是什么,怎么用,是否能解决线程安全问题,非常nice。但个人认为讲解存在遗漏,进行如下示例补充:
- InheritableThreadLocal
public class ThreadIdService { private static ThreadLocal<User> localUser=new InheritableThreadLocal<>(); public static void main(String[] args) { User user = new User(); user.setName("main"); localUser.set(user); System.out.println("main threadUser:"+localUser.get()); Thread t1 = new Thread() { @Override public void run() { System.out.println("t1User:"+localUser.get()); localUser.get().setName("1"); System.out.println("t1User:"+localUser.get()); } }; Thread t2 = new Thread() { @Override public void run() { User user2 = new User(); user2.setName("2"); localUser.set(user2); System.out.println("t2User:"+localUser.get()); } }; t1.start(); t2.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main threadUser:" + localUser.get()); user.setName("main2"); } }
- ThreadLocal
public class ThreadIdService { private static ThreadLocal<User> localUser=new ThreadLocal<>(); public static void main(String[] args) { User user = new User(); user.setName("main"); localUser.set(user); System.out.println("main threadUser:"+localUser.get()); Thread t1 = new Thread() { @Override public void run() { System.out.println("t1User:"+localUser.get()); /*localUser.get().setName("1"); System.out.println("t1User:"+localUser.get());*/ } }; Thread t2 = new Thread() { @Override public void run() { User user2 = new User(); user2.setName("2"); localUser.set(user2); System.out.println("t2User:"+localUser.get()); } }; t1.start(); t2.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main threadUser:" + localUser.get()); user.setName("main2"); } }
- 总结:
- ThreadLocal能起到线程件变量隔离的作用。
- InheritableThreadLocal则未必,若每个线程存放在InheritableThreadLocal的变量都采用new Object()的方式,则各线程间互不影响,否则传递的是引用,牵一发而动全身!!!
- InheritableThreadLocal之所以能够完成线程间变量的传递,是在new Thread()的时候对inheritableThreadLocals对像里的值进行了复制。
- 子线程通过继承得到的InheritableThreadLocal里的值与父线程里的InheritableThreadLocal的值具有相同的引用,如果父子线程想实现不影响各自的对象,可以重写InheritableThreadLocal的childValue方法。