保存线程的独立变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数之间公共变量传递麻烦。

需要给不同的线程保存不同的信息时。
public class TestThreadLocal {
    private static ThreadLocal threadLocal=new ThreadLocal();
//    private static ThreadLocal threadLocal=new ThreadLocal(){
//
//        @Override
//        protected Integer initialValue() {
//            return 0;
//        }
//    };
    public static void main(String[] args) {
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(threadLocal.get());
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set(3);
                System.out.println("t2:"+threadLocal.get());
            }
        });
        t1.start();
        t2.start();
        System.out.println(threadLocal.get());
    }
}    如果需要设置默认值的话,可以实现initialValue方法。
典型场景1:我们知道SimpleDateFormat的对象如果多线程使用的话会有线程不安全的问题。具体代码如下:
public class TestThreadLocal {
    public static ExecutorService executorService = Executors.newFixedThreadPool(16);
    private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException {
       for (int i=0;i<1000;i++){
           executorService.submit(new Runnable() {
               @Override
               public void run(){
                   String format = simpleDateFormat.format(new Date());
                   try {
                       Date parse = simpleDateFormat.parse("2021-09-01 00:00:00");
                   } catch (ParseException e) {
                       e.printStackTrace();
                   }
                   System.out.println(format);
               }
           });
       }
       Thread.sleep(3000);
        executorService.shutdownNow();
    }
}运行结果如下:
可以看出,发生了异常。
方法1:我们可以改为每次都new一个新的SimpleDateFormat对象的话,这样再运行是没问题的。但是有些资源浪费。
方法2:使用ThreadLocal来解决。假设线程池里共16个线程,那我们总共16个SimpleDateFormat对象就可以应付所有的日期格式化的调用。
代码如下:
public class TestThreadLocal {
    public static ExecutorService executorService = Executors.newFixedThreadPool(16);
    private static ThreadLocal threadLocal=new ThreadLocal(){
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };
    private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException {
       for (int i=0;i<1000;i++){
           executorService.submit(new Runnable() {
               @Override
               public void run() {
                   String format = threadLocal.get().format(new Date());
                   try {
                       Date parse = threadLocal.get().parse("2021-09-01 00:00:00");
                   } catch (ParseException e) {
                       e.printStackTrace();
                   }
                   System.out.println(format);
               }
           });
       }
       Thread.sleep(3000);
        executorService.shutdownNow();
    }
}  注意: 如果不使用线程池,线程结束,线程里的threadLocalMap也会被回收。但是如果使用线程池,线程池里面的线程会被复用,线程里的threadLocalMap不会被回收,就造成了内存泄漏。按照正确的使用方法应该是每次用完了remove,但是这样效率就很低。还不如方法1每次去new一个新的SimpleDateFormat对象。(但个人觉得其实还好,泄漏一点也没关系,不过threadlocal毕竟不是专门解决线程安全问题的,不推荐这么用)
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
试想:
一个线程对应一块工作内存,线程可以存储多个ThreadLocal。那么假设,开启1万个线程,每个线程创建1万个ThreadLocal,也就是每个线程维护1万个ThreadLocal小内存空间,而且当线程执行结束以后,假设这些ThreadLocal里的Entry还不会被回收,那么将很容易导致堆内存溢出。
怎么办?难道JVM就没有提供什么解决方案吗?
答案:
ThreadLocal的关系图如下所示:
Thread里面维护了一个ThreadLocalMap,这个map里面的key是弱引用的readLocal实例。value是我们设置进去的值。当把treadLocal实例对象置为null后,没有任何强引用指向threadLocal实例,所以theadLocal将会被gc回收。但是我们的value不会被回收,因为存在一个thread连接过来的强引用。只有当thread结束后,强引用断开,map、value等将全部被回收。
如下图:
但是很多时候我们使用线程池,为了复用线程,thread生命周期没有结束,所以无法回收,造成内存泄漏。
                分享文章:阿里二面:ThreadLocal为什么会内存泄露
                
                新闻来源:http://www.csdahua.cn/qtweb/news27/367327.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网