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