1.线程本地变量,使用方式
public class ThreadLocalDemo { public static class ThreadLocalWrapper { static ThreadLocal<Integer> count = new ThreadLocal<>(); } public static class ThreadLocalSet{ private void setCount() { ThreadLocalWrapper.count.set(1); } } public static class ThreadLocalPrint{ private static void printCount() { System.out.println("count:"+ThreadLocalWrapper.count.get()); } } public static void main(String[] args) { ThreadLocalSet set = new ThreadLocalSet(); set.setCount(); ThreadLocalPrint.printCount(); } }
以上代码输出: count:1,实现了隐式传参。
2.线程本地变量创建过程
2.1.实例化时根据hash种子自增方式创建hashCode
2.2.线程中赋值时,线程中如果threadLocals为空则 threadLocals = new ThreadLocalMap(this,value);其中this指当前的TreadLocal对象
2.2.1ThreadLocalMap的set操作会创建一个entry,entry中的key被定义为弱引用,再根据threadLocal对象中的hashCode算出其在hash桶中的位置并放置在该位置,如发现该位置有其他ThreadLocal则位置+1。
2.3.删除过程即将entry删除
3.hash寻址与HashMap的区别,解决哈希冲突的算法不一样。HashMap使用的是链地址法。ThreadLocalMap使用的是开放寻址法。
4.怎样理解使用弱引用是为解决内存泄露。为此需要将以上代码改一下:
public class ThreadLocalDemo { public static class ThreadLocalWrapper { static ThreadLocal<Integer> count = new ThreadLocal<>(); } public static class ThreadLocalSet{ private void setCount() { //每次使用前创建一个新的ThreadLocal ThreadLocalWrapper.count = new ThreadLocal<>(); ThreadLocalWrapper.count.set(1); } } public static class ThreadLocalPrint{ private static void printCount() { System.out.println("count:"+ThreadLocalWrapper.count.get()); } } public static void main(String[] args) { //创建一个只有一个线程的线程池,线程重复使用 ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); for(int i=1;i<=1000;i++){ executor.execute(()->{ ThreadLocalSet set = new ThreadLocalSet(); set.setCount(); ThreadLocalPrint.printCount(); //使用完之后通常做法不会手动做remove操作 //ThreadLocalWrapper.count.remove(); }); } } }
执行1000次
如果是threadLocalMap.entry.key是强引用,则在垃圾回收时所有ThreadLocal对象都不能回收。
如果是threadLocalMap.entry.key是弱引用,则只有当前时间点的唯一一个在ThreadLocalWrapper .count静态变量上建立了强引用,其他对象则被回收。
更简单举例:
public class ThreadLocalDemo2 { public static void main(String[] args) { ThreadLocal<Integer> count; while(true){ count = new ThreadLocal<>(); count.set(1); count.get(); } } }
while每次循环都创建新的TrheadLocal对象,会在当前线程的ThreadLocalMap中插入entry,强引用情况下所有entry都不能释放。弱引用情况下,除当前使用的ThreadLocal之外都只有弱引用。因此可被回收。
使用简单举例代码跑出来的结果,未发现溢出
entry存在变小的情况,因此也在被回收。