ThreadLocal与线程池结合使用时,如何避免哪些潜在问题?

2026-05-22 08:112阅读0评论SEO教程
  • 内容介绍
  • 相关推荐

本文共计431个文字,预计阅读时间需要2分钟。

ThreadLocal与线程池结合使用时,如何避免哪些潜在问题?

直接从线程池中获取主线程或非主线程池中ThreadLocal设置的变量的值,例如:

javaprivate static final ThreadPoolExecutor syncAccessPool=new ThreadPoolExecutor(50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(6));

直接先线程池中获取主线程或非线程池中的ThreadLocal设置的变量的值

例如

private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor( 50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(600) ); public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); threadLocal.set("userId115807"); syncAccessPool.execute(()->{ System.out.println(threadLocal.get()); }); }

最后打印的结果是null


解决办法:真实使用中相信大家不会这么使用的,但是我出错主要是因为使用了封装的方法,封装的方法中使用了ThreadLocal,这种情况下要先从ThreadLocal中获取到方法中,再设置到线程池

线程池中使用了ThreadLocal设置了值但是使用完后并未移除造成内存飙升或OOM

public class ThreadLocalOOM { static class LocalVariable{ private Long[] a = new Long[1024*1024]; } private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor( 50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(600) ); final static ThreadLocal<LocalVariable> threadLocal = new ThreadLocal<LocalVariable>(); public static void main(String[] args) throws InterruptedException { Thread.sleep(10000); for (int i=0;i<100;i++){ syncAccessPool.execute(()->{ threadLocal.set(new LocalVariable()); System.out.println("use local variable"); }); Thread.sleep(1000); } System.out.println("pool execute over"); } }

这个程序使用jconsole程序观察到的内存变化为

在使用完之后remove之后的内存变化

public static void main(String[] args) throws InterruptedException { for (int i=0;i<100;i++){ syncAccessPool.execute(()->{ threadLocal.set(new LocalVariable()); System.out.println("use local variable"); threadLocal.remove(); }); Thread.sleep(1000); } System.out.println("pool execute over"); }

ThreadLocal与线程池结合使用时,如何避免哪些潜在问题?

内存相比之前降低了几倍。这个原因就是没有remove,线程池中所有存在的线程都会持有这个本地变量,导致内存暴涨。如果将private Long[] a = new Long[1024*1024]; 扩大可能就会很快抛出OOM异常

本文共计431个文字,预计阅读时间需要2分钟。

ThreadLocal与线程池结合使用时,如何避免哪些潜在问题?

直接从线程池中获取主线程或非主线程池中ThreadLocal设置的变量的值,例如:

javaprivate static final ThreadPoolExecutor syncAccessPool=new ThreadPoolExecutor(50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(6));

直接先线程池中获取主线程或非线程池中的ThreadLocal设置的变量的值

例如

private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor( 50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(600) ); public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); threadLocal.set("userId115807"); syncAccessPool.execute(()->{ System.out.println(threadLocal.get()); }); }

最后打印的结果是null


解决办法:真实使用中相信大家不会这么使用的,但是我出错主要是因为使用了封装的方法,封装的方法中使用了ThreadLocal,这种情况下要先从ThreadLocal中获取到方法中,再设置到线程池

线程池中使用了ThreadLocal设置了值但是使用完后并未移除造成内存飙升或OOM

public class ThreadLocalOOM { static class LocalVariable{ private Long[] a = new Long[1024*1024]; } private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor( 50, 80, 8000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(600) ); final static ThreadLocal<LocalVariable> threadLocal = new ThreadLocal<LocalVariable>(); public static void main(String[] args) throws InterruptedException { Thread.sleep(10000); for (int i=0;i<100;i++){ syncAccessPool.execute(()->{ threadLocal.set(new LocalVariable()); System.out.println("use local variable"); }); Thread.sleep(1000); } System.out.println("pool execute over"); } }

这个程序使用jconsole程序观察到的内存变化为

在使用完之后remove之后的内存变化

public static void main(String[] args) throws InterruptedException { for (int i=0;i<100;i++){ syncAccessPool.execute(()->{ threadLocal.set(new LocalVariable()); System.out.println("use local variable"); threadLocal.remove(); }); Thread.sleep(1000); } System.out.println("pool execute over"); }

ThreadLocal与线程池结合使用时,如何避免哪些潜在问题?

内存相比之前降低了几倍。这个原因就是没有remove,线程池中所有存在的线程都会持有这个本地变量,导致内存暴涨。如果将private Long[] a = new Long[1024*1024]; 扩大可能就会很快抛出OOM异常