溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java如何使用ThreadLocal存儲線程專有對象

發(fā)布時間:2022-03-11 11:42:31 來源:億速云 閱讀:356 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下java如何使用ThreadLocal存儲線程專有對象,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

使用ThreadLocal存儲線程專有對象

ThreadLocal提供了線程專有對象,可以在整個線程生命周期中隨時取用,極大地方便了一些邏輯的實現(xiàn)。

常見的ThreadLocal用法主要有兩種:

  1. 保存線程上下文對象,避免多層級參數(shù)傳遞;

  2. 保存非線程安全對象,避免多線程并發(fā)調(diào)用。

1.保存線程上下文對象,避免多層級參數(shù)傳遞

這里,以PageHelper插件的源代碼中的分頁參數(shù)設(shè)置與使用為例說明。

設(shè)置分頁參數(shù)代碼:

/** 分頁方法類 */public abstract class PageMethod {    /** 本地分頁 */
    protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();    /** 設(shè)置分頁參數(shù) */
    protected static void setLocalPage(Page page) {
        LOCAL_PAGE.set(page);
    }    /** 獲取分頁參數(shù) */
    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;
    }
}

使用分頁參數(shù)代碼:

/** 虛輔助方言類 */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);
    }
    ...
}

使用分頁插件代碼:

/** 查詢用戶函數(shù) */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;
}

如果要把分頁參數(shù)通過函數(shù)參數(shù)逐級傳給查詢語句,除非修改MyBatis相關(guān)接口函數(shù),否則是不可能實現(xiàn)的。

2.保存非線程安全對象,避免多線程并發(fā)調(diào)用

在寫日期格式化工具函數(shù)時,首先想到的寫法如下:

/** 日期模式 */private static final String DATE_PATTERN = "yyyy-MM-dd";/** 格式化日期函數(shù) */public static String formatDate(Date date) {    return new SimpleDateFormat(DATE_PATTERN).format(date);
}

其中,每次調(diào)用都要初始化DateFormat導致性能較低,把DateFormat定義成常量后的寫法如下:

/** 日期格式 */private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");/** 格式化日期函數(shù) */public static String formatDate(Date date) {    return DATE_FORMAT.format(date);
}

由于SimpleDateFormat是非線程安全的,當多線程同時調(diào)用formatDate函數(shù)時,會導致返回結(jié)果與預(yù)期不一致。如果采用ThreadLocal定義線程專有對象,優(yōu)化后的代碼如下:

/** 本地日期格式 */private static final ThreadLocal<DateFormat> LOCAL_DATE_FORMAT = new ThreadLocal<DateFormat>() {    @Override
    protected DateFormat initialValue() {        return new SimpleDateFormat("yyyy-MM-dd");
    }
};/** 格式化日期函數(shù) */public static String formatDate(Date date) {    return LOCAL_DATE_FORMAT.get().format(date);
}

這是在沒有線程安全的日期格式化工具類之前的實現(xiàn)方法。在JDK8以后,建議使用DateTimeFormatter代替SimpleDateFormat,因為SimpleDateFormat是線程不安全的,而DateTimeFormatter是線程安全的。當然,也可以采用第三方提供的線程安全日期格式化函數(shù),比如apache的DateFormatUtils工具類。

注意:ThreadLocal有一定的內(nèi)存泄露的風險,盡量在業(yè)務(wù)代碼結(jié)束前調(diào)用remove函數(shù)進行數(shù)據(jù)清除。

以上是“java如何使用ThreadLocal存儲線程專有對象”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI