文档章节

ThreadLocal的应用

4rnold
 4rnold
发布于 2017/09/11 00:25
字数 569
阅读 16
收藏 0

ThreadLocal 内存泄露问题

ThreadLocal本身不存储值,他只作为一个key。真正存值的是thread

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;//t.threadLocals是ThreadLocal.ThreadLocalMap类型
}

输入图片说明

也就是说,threadlocal的生命周期是一个普通的变量的生命周期,而threadLocal中存放的数据的生命周期是当前thread的生命周期(thread不销毁一直都存在)。如果遇到thread不销毁的情况,比如使用线程池,不断创建新的threadLocal作为key 向 Thread.threadLocals中插入对象,而之前的对象也不会被回收,因为有Thread.threadLocals的引用。这样会造成内存泄露。所以需要在使用完成后,手动从threadLocal中删除数据。

ThreadLocal 应用

通常我们写一个工具类都是无状态的。例如下面写一个db的工具类。

public class DatabaseHelper1 {

    private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class);
    private static final String DRIVER;
    private static final String URL;
    private static final String USERNAME;
    private static final String PASSWORD;

    static {
        Properties conf = PropsUtil.loadProps("config.properties");
        String driver = conf.getProperty("jdbc.driver");
        String url = conf.getProperty("jdbc.url");
        String username = conf.getProperty("jdbc.username");
        String password = conf.getProperty("jdbc.password");

        DRIVER = driver;
        URL = url;
        USERNAME = username;
        PASSWORD = password;
    }

  //示例代码
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }

  //示例代码
    public static <T>List<T> queryEntityList(Connection connection, Class<T> entityClass, String sql, Object... params) {
        return new ArrayList<>();
    }
}

这样的话service调用就比较麻烦

    public List<Customer> getCustomerList1() throws SQLException {
        Connection connection = DatabaseHelper1.getConnection();
        String sql = "select * from customer";
        return DatabaseHelper1.queryEntityList(connection,Customer.class, sql);
    }

能不能让DatabaseHelper工具类有记忆功能?不用每次service都是先取到connection再做其他操作。threadLocal可以帮我们实现。

public class DatabaseHelper {
      private static ThreadLocal<Connection> threadConnection = new ThreadLocal<>();

      public static Connection getConnection() {
        Connection connection = threadConnection.get();
        if (connection == null) {
            try {
                connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            } catch (SQLException e) {
                LOGGER.error("get connection fail");
            } finally {
                threadConnection.set(connection);
            }
        }
        return connection;
    }
  
      public static void closeConnetion(Connection connection) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                LOGGER.error("close connection fail");
            } finally {
                threadConnection.remove();
            }
        }
    }
  
      public static <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
        List<T> entityList = new ArrayList<>();
        Connection connection = getConnection();
        try {
            entityList = QUERY_RUNNER.query(connection, sql, new BeanListHandler<T>(entityClass), params);
        } catch (SQLException e) {
            LOGGER.error("queryEntity fail", e);
        } finally {
            closeConnetion(connection);
        }
        return entityList;
    }
}

通过threadLocal,使service调用变的简单

public List<Customer> getCustomerList() {
   	String sql = "select * from customer";
  	return DatabaseHelper.queryEntityList(Customer.class, sql);
}

但是还记得上面提到的threadlocal内存泄露么,在每次使用完threadLocal记得将其内容删除。就是closeConnection()中的threadConnection.remove();

© 著作权归作者所有

共有 人打赏支持
4rnold
粉丝 1
博文 51
码字总数 26866
作品 0
深圳
程序员
一句话讲清楚什么是JavaEE

Java技术不仅是一门编程语言而且是一个平台。同时Java语言是一门有着特定语法和风格的高级的面向对象的语言,Java平台是Java语言编写的特定应用程序运行的环境。Java平台有很多种,很多的Jav...

qq58edeba279279
06/26
0
0
一句话讲清楚什么是JavaEE

摘要: Java技术不仅是一门编程语言而且是一个平台。同时Java语言是一门有着特定语法和风格的高级的面向对象的语言,Java平台是Java语言编写的特定应用程序运行的环境。Java平台有很多种,很多...

qq592fbb5b34ad7
07/02
0
0
浅谈Java SE、Java EE、Java ME三者的区别

现在一个个来分析 1. Java SE(Java Platform,Standard Edition)。Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了...

空天啸鹤
2015/08/07
0
0
什么是Java语言?java语言简介

Java是由Sun Microsystems公司于1995年5月推出的Java程序设计语言(以下简称Java语言)和Java平台的总称。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的W...

阿秀a
2010/10/19
0
0
《Java从小白到大牛精简版》之第1章 开篇综述

Java诞生到现在已经有20多年了,但是Java仍然是非常热门的编程语言之一,很多平台中使用Java开发。表1-1所示的是TIOBE社区发布的2016年5月和2017年5月的编程语言排行榜,可见Java语言的热度,...

tony关东升
06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Docker和Kubernetes如何让DevOps更具效力

缩短time-to-makrt对于任何一家企业都至关重要,这直接决定了客户满意度、市场竞争力乃至盈利能力。但在部署应用时,大多数企业内的IT团队都或多或少会遇到Dev和Ops之间的问题,这两个部门围...

好雨云帮
14分钟前
0
0
OSChina 周一乱弹 —— 嫂子我帮你们照顾放心吧

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @clouddyy :#每日一歌# 《绿光 - 孙燕姿》 《绿光》 - 孙燕姿 手机党少年们想听歌,请使劲儿戳(这里) @凝小紫:又到周日了,按照惯例吐槽一...

小小编辑
35分钟前
41
5
可爱的python测试开发库(python测试开发工具库汇总)

欢迎转载,转载请注明来源: github地址 谢谢点赞 本文地址 相关书籍下载 测试开发 Web UI测试自动化 splinter - web UI测试工具,基于selnium封装。 链接 selenium - web UI自动化测试。 链...

python测试开发人工智能安全
今天
2
0
Shiro | 实现权限验证完整版

写在前面的话 提及权限,就会想到安全,是一个十分棘手的话题。这里只是作为学校Shiro的一个记录,而不是,权限就应该这样设计之类的。 Shiro框架 1、Shiro是基于Apache开源的强大灵活的开源...

冯文议
今天
1
0
linux 系统的运行级别

运行级别 运行级别 | 含义 0 关机 1 单用户模式,可以想象为windows 的安全模式,主要用于修复系统 2 不完全的命令模式,不含NFS服务 3 完全的命令行模式,就是标准的字符界面 4 系统保留 5 ...

Linux学习笔记
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部