您好,登錄后才能下訂單哦!
小編給大家分享一下java如何使用ThreadLocal存儲線程專有對象,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
ThreadLocal提供了線程專有對象,可以在整個線程生命周期中隨時取用,極大地方便了一些邏輯的實現。
常見的ThreadLocal用法主要有兩種:
保存線程上下文對象,避免多層級參數傳遞;
保存非線程安全對象,避免多線程并發調用。
這里,以PageHelper插件的源代碼中的分頁參數設置與使用為例說明。
設置分頁參數代碼:
/** 分頁方法類 */public abstract class PageMethod { /** 本地分頁 */ protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>(); /** 設置分頁參數 */ protected static void setLocalPage(Page page) { LOCAL_PAGE.set(page); } /** 獲取分頁參數 */ public static <T> Page<T> getLocalPage() { return LOCAL_PAGE.get(); } /** 開始分頁 */ public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) { Page<E> page = new Page<E>(pageNum, pageSize, count); page.setReasonable(reasonable); page.setPageSizeZero(pageSizeZero); Page<E> oldPage = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } }
使用分頁參數代碼:
/** 虛輔助方言類 */public abstract class AbstractHelperDialect extends AbstractDialect implements Constant { /** 獲取本地分頁 */ public <T> Page<T> getLocalPage() { return PageHelper.getLocalPage(); } /** 獲取分頁SQL */ @Override public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); Page page = getLocalPage(); String orderBy = page.getOrderBy(); if (StringUtil.isNotEmpty(orderBy)) { pageKey.update(orderBy); sql = OrderByParser.converToOrderBySql(sql, orderBy); } if (page.isOrderByOnly()) { return sql; } return getPageSql(sql, page, pageKey); } ... }
使用分頁插件代碼:
/** 查詢用戶函數 */public PageInfo<UserDO> queryUser(UserQuery userQuery, int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<UserDO> userList = userDAO.queryUser(userQuery); PageInfo<UserDO> pageInfo = new PageInfo<>(userList); return pageInfo; }
如果要把分頁參數通過函數參數逐級傳給查詢語句,除非修改MyBatis相關接口函數,否則是不可能實現的。
在寫日期格式化工具函數時,首先想到的寫法如下:
/** 日期模式 */private static final String DATE_PATTERN = "yyyy-MM-dd";/** 格式化日期函數 */public static String formatDate(Date date) { return new SimpleDateFormat(DATE_PATTERN).format(date); }
其中,每次調用都要初始化DateFormat導致性能較低,把DateFormat定義成常量后的寫法如下:
/** 日期格式 */private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");/** 格式化日期函數 */public static String formatDate(Date date) { return DATE_FORMAT.format(date); }
由于SimpleDateFormat是非線程安全的,當多線程同時調用formatDate函數時,會導致返回結果與預期不一致。如果采用ThreadLocal定義線程專有對象,優化后的代碼如下:
/** 本地日期格式 */private static final ThreadLocal<DateFormat> LOCAL_DATE_FORMAT = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } };/** 格式化日期函數 */public static String formatDate(Date date) { return LOCAL_DATE_FORMAT.get().format(date); }
這是在沒有線程安全的日期格式化工具類之前的實現方法。在JDK8以后,建議使用DateTimeFormatter代替SimpleDateFormat,因為SimpleDateFormat是線程不安全的,而DateTimeFormatter是線程安全的。當然,也可以采用第三方提供的線程安全日期格式化函數,比如apache的DateFormatUtils工具類。
注意:ThreadLocal有一定的內存泄露的風險,盡量在業務代碼結束前調用remove函數進行數據清除。
以上是“java如何使用ThreadLocal存儲線程專有對象”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。