最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的SimpleDateFormat的線程安全問題詳解

 更新時(shí)間:2024年01月10日 09:46:31   作者:愛coding的同學(xué)  
這篇文章主要介紹了Java中的SimpleDateFormat的線程安全問題詳解,sonar 是一個(gè)代碼質(zhì)量管理工具,SonarQube是一個(gè)用于代碼質(zhì)量管理的開放平臺(tái),為項(xiàng)目提供可視化報(bào)告, 連續(xù)追蹤項(xiàng)目質(zhì)量演化過程,需要的朋友可以參考下

起因

sonar 是一個(gè)代碼質(zhì)量管理工具,SonarQube是一個(gè)用于代碼質(zhì)量管理的開放平臺(tái)。

為項(xiàng)目提供可視化報(bào)告,連續(xù)追蹤項(xiàng)目質(zhì)量演化過程。

通過插件機(jī)制,Sonar可以集成不同的測(cè)試工具,代碼分析工具,以及持續(xù)集成工具。

對(duì)結(jié)果進(jìn)行再加工處理,通過量化的方式度量代碼質(zhì)量的變化。

某天它揭露了代碼里這樣一個(gè)級(jí)別為嚴(yán)重的違規(guī)。

SimpleDateFormat 源碼解析

根據(jù) sonar 的提示,SimpleDateFormat 的 format 方法可能存在線程安全的問題,那么來看下SimpleDateFormat 的源碼,看看是否如此

// Called from Format after creating a FieldDelegate
    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
        calendar.setTime(date);
        boolean useDateFormatSymbols = useDateFormatSymbols();
        for (int i = 0; i < compiledPattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            }
            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;
            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;
            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }

當(dāng)看到高亮的那行代碼時(shí),就基本可以認(rèn)定 SimpleDateFormat.format() 不是線程安全的:在多線程環(huán)境下,每次調(diào)用 format 方法時(shí),calendar 都會(huì)將時(shí)間設(shè)置為傳入的時(shí)間,這樣如果上一個(gè)線程的 format 方法還在執(zhí)行中,肯定會(huì)導(dǎo)致輸出的結(jié)果不正確。

如何做到線程安全

那么怎么做才能線程安全呢?

不用靜態(tài)屬性

每次需要格式化日期時(shí),new 一個(gè) DateFormat,保證線程安全,我們可以這樣“優(yōu)化”一下

String inputValue = game.getId() + new SimpleDateFormat( "yyyyMMdd" ).format( new Date() );

雖然線程安全了,但是這樣性能就下降了,如果這段代碼頻繁的調(diào)用,不僅 new 一個(gè) DateFormat 對(duì)象的代價(jià)有點(diǎn)大,而且頻繁的 new 也會(huì)導(dǎo)致 gc 的壓力增大

同步或者加鎖

既然 format() 方法線程不安全,那就在調(diào)用時(shí)采用同步或加鎖,例如

private static SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd" );// 設(shè)置日期格式
	private static final Lock LOCK = new ReentrantLock();
	@Override
	public void addGame( Game game ) {
		......
		LOCK.lock();
		try {
			String inputValue = game.getId() + df.format( new Date() );
		} finally {
			LOCK.unlock();
		}
		......
	}

DateFormat 池

加鎖是解決了線程安全的問題,也不會(huì)因?yàn)?new 出太多的 DateFormat 增加 gc 的負(fù)擔(dān),但是很顯然并發(fā)性能大大的降低了,如果在并發(fā)性要求較高的場(chǎng)合,還不如 new 一個(gè)的性能高呢,那有什么辦法再優(yōu)化一下嗎

可以實(shí)現(xiàn)一個(gè) DateFormat 池,實(shí)現(xiàn)如下功能

1. 設(shè)定池的大小,在池實(shí)例化的同時(shí),實(shí)例化一批 DateFormat

2. 每個(gè) DateFormat 都有一個(gè)狀態(tài),表明當(dāng)前是空閑還是忙,初始狀態(tài)為空閑

3. 當(dāng)需要格式化日期時(shí),從池里取出一個(gè)空閑的 DateFormat,同時(shí)將其標(biāo)記為忙

4. 池里的 DateFormat 的 format 方法需要重寫,在 format 完成后將其狀態(tài)標(biāo)記為空閑

用池的優(yōu)勢(shì)很明顯:只要設(shè)定合適的池大小,就不用擔(dān)心并發(fā)性能;并且也不存在增加 gc 負(fù)擔(dān)的問題;當(dāng)然池的實(shí)現(xiàn)比較復(fù)雜,而且池內(nèi)部也要解決線程安全問題,可以考慮采用一些開源的池框架例如 Apache commons pool 來做

ThreadLocal<DateFormat>

在引入 ThreadLocal 之前,思考一下這個(gè)問題:如果只有一個(gè)線程,format 方法還存在線程安全問題嗎? 顯然不會(huì),如果只有一個(gè)線程,那么 format 方法實(shí)際上是串行執(zhí)行的,絕無可能并行執(zhí)行;那么,如果在多線程環(huán)境下,給每個(gè)線程都分配一個(gè)固定的 DateFormat 來執(zhí)行 format 方法,顯然也不會(huì)有線程安全的問題了 ThreadLocal 就是用于這種思路的一個(gè)解決方案:為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。 ThreadLocal 的使用如下

private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final ThreadLocal<DateFormat> SDF  = new ThreadLocal<DateFormat>() {
    protected synchronized DateFormat initialValue() {
        return new SimpleDateFormat(
            DATE_FORMAT);
                }
        };
            ......
album.setReleaseDate(SDF.get().parse(show.getReleasedate().substring(0, 10))); // 發(fā)布日期

先看每次都 new 一個(gè)新對(duì)象和 ThreaLocal之間的差別,假設(shè)有 1 個(gè)線程要執(zhí)行 n 次 format

1. new:n 個(gè)實(shí)例

2. ThreadLocal:1 個(gè)實(shí)例.但是,如果是 n 個(gè)線程,每個(gè)線程只執(zhí)行 1 次 format 呢?

 new:n 個(gè)實(shí)例

 ThreadLocal:n 個(gè)實(shí)例

很顯然,如果使用 ThreadLocal 的話,線程應(yīng)該是能復(fù)用的,否則和 new 的效果是一樣滴

再看加鎖和池的差別,主要表現(xiàn)在并發(fā)性能方面,加鎖實(shí)際導(dǎo)致了串行化,不滿足高并發(fā)的場(chǎng)合

再看下池和 ThreadLocal的差別

3. 并發(fā)性能上2者都很優(yōu)秀

4. 相對(duì)來說 ThreadLocal 的實(shí)現(xiàn)更簡(jiǎn)單,而且完全不需要加鎖或同步,而池在管理池內(nèi)的元素時(shí)免不了需要加鎖或同步

5. 池的復(fù)用性最好,而 ThreadLocal 的復(fù)用性則完全取決于其宿主線程的復(fù)用性

到此這篇關(guān)于Java中的SimpleDateFormat的線程安全問題詳解的文章就介紹到這了,更多相關(guān)SimpleDateFormat線程安全問題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot如何通過接口實(shí)現(xiàn)動(dòng)態(tài)二維碼的定時(shí)刷新

    springboot如何通過接口實(shí)現(xiàn)動(dòng)態(tài)二維碼的定時(shí)刷新

    這篇文章主要為大家詳細(xì)介紹了springboot如何通過接口實(shí)現(xiàn)動(dòng)態(tài)二維碼的定時(shí)刷新功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-05-05
  • 三種java編程方法實(shí)現(xiàn)斐波那契數(shù)列

    三種java編程方法實(shí)現(xiàn)斐波那契數(shù)列

    這篇文章主要為大家詳細(xì)介紹了三種java編程方法實(shí)現(xiàn)斐波那契數(shù)列,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 使用Spring Data R2DBC +Postgres實(shí)現(xiàn)增刪改查功能

    使用Spring Data R2DBC +Postgres實(shí)現(xiàn)增刪改查功能

    這篇文章主要介紹了使用Spring Data R2DBC +Postgres實(shí)現(xiàn)增刪改查功能,本文通過兩種方法給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • SpringBoot項(xiàng)目與Nacos配置全過程

    SpringBoot項(xiàng)目與Nacos配置全過程

    本文介紹了如何在SpringBoot項(xiàng)目中使用Nacos作為配置中心,實(shí)現(xiàn)動(dòng)態(tài)配置管理和實(shí)時(shí)更新配置的能力,通過配置命名空間和yml文件,創(chuàng)建SpringBoot項(xiàng)目并添加Nacos依賴,編寫Controller和啟動(dòng)類,配置Tomcat啟動(dòng)程序,最終在Nacos服務(wù)端注冊(cè)成功
    2024-11-11
  • windows下 jdk1.7安裝教程圖解

    windows下 jdk1.7安裝教程圖解

    java編程的初學(xué)者在開始編碼前都會(huì)遇到一個(gè)難題,那就是jdk1.7環(huán)境變量配置怎么操作,怎么安裝,針對(duì)這個(gè)難題,小編特地為大家整理相關(guān)教程,不了解的朋友可以前往查看使用
    2018-05-05
  • SpringBoot集成Mybatis-plus并實(shí)現(xiàn)自動(dòng)生成相關(guān)文件的示例代碼

    SpringBoot集成Mybatis-plus并實(shí)現(xiàn)自動(dòng)生成相關(guān)文件的示例代碼

    Mybatis-Plus是一個(gè)優(yōu)秀的Mybatis增強(qiáng)工具,目前更新到3.1.1,本文通過示例代碼給大家介紹SpringBoot集成Mybatis-plus并實(shí)現(xiàn)自動(dòng)生成相關(guān)文件的問題,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的示例代碼

    SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的示例代碼

    在實(shí)際開發(fā)中,參數(shù)校驗(yàn)是保障系統(tǒng)穩(wěn)定和數(shù)據(jù)可靠性的重要措施,Aviator 是一個(gè)高性能的表達(dá)式引擎,它能夠簡(jiǎn)化復(fù)雜的邏輯判斷并提升參數(shù)校驗(yàn)的靈活性,本文將介紹如何在 Spring Boot 中集成 Aviator,并利用它來實(shí)現(xiàn)靈活的參數(shù)校驗(yàn),需要的朋友可以參考下
    2025-02-02
  • Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    mybatis和jpa兩個(gè)持久層框架,從底層到用法都不同,但是實(shí)現(xiàn)的功能是一樣的,所以說一直以來頗有爭(zhēng)議,所以下面這篇文章主要給大家介紹了關(guān)于Mybatis與Jpa的區(qū)別和性能對(duì)比的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • java-SSH2實(shí)現(xiàn)數(shù)據(jù)庫和界面的分頁

    java-SSH2實(shí)現(xiàn)數(shù)據(jù)庫和界面的分頁

    本文主要是介紹SSH2實(shí)現(xiàn)數(shù)據(jù)庫和界面的分頁的代碼,分頁在web應(yīng)用中是經(jīng)常要做的事情,實(shí)用性比較大,有需要的朋友可以來了解一下。
    2016-10-10
  • Java設(shè)計(jì)模式——工廠設(shè)計(jì)模式詳解

    Java設(shè)計(jì)模式——工廠設(shè)計(jì)模式詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式——工廠設(shè)計(jì)模式詳解,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11

最新評(píng)論

丹江口市| 平定县| 宣威市| 壶关县| 德化县| 黑河市| 丽水市| 襄汾县| 沧源| 南召县| 灵寿县| 盐边县| 沙田区| 宜川县| 南乐县| 兴安县| 葵青区| 灌云县| 得荣县| 桑植县| 礼泉县| 伽师县| 读书| 松原市| 临沭县| 阳新县| 都江堰市| 鄂托克前旗| 饶河县| 阆中市| 定南县| 桓台县| 宣汉县| 阿拉善右旗| 达拉特旗| 民丰县| 微山县| 酉阳| 大新县| 尼勒克县| 岳池县|