ThreadLocal自己不存储值,他只做为一个key。真正存值的是threadjava
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中删除数据。sql
一般咱们写一个工具类都是无状态的。例以下面写一个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调用就比较麻烦this
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能够帮咱们实现。url
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();code