一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java8新特性之線程安全日期類

Java8新特性之線程安全日期類

2021-09-08 10:55wzq_55552 Java教程

這篇文章主要介紹了Java8新特性之線程安全日期類,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有一定的幫助,需要的朋友可以參考下

localdatetime

java8新特性之一,新增日期類。

在項目開發(fā)過程中經(jīng)常遇到時間處理,但是你真的用對了嗎,理解阿里巴巴開發(fā)手冊中禁用static修飾simpledateformat嗎

通過閱讀本篇文章你將了解到:

  • 為什么需要localdate、localtime、localdatetime【java8新提供的類】
  • java8新的時間api的使用方式,包括創(chuàng)建、格式化、解析、計算、修改

可以使用instant代替 date,localdatetime代替 calendar,datetimeformatter 代替 simpledateformat。

simpledateformat線程不安全

date如果不格式化,打印出的日期可讀性差

?
1
tue sep 10 09:34:04 cst 2019

使用simpledateformat對時間進行格式化,但simpledateformat是線程不安全的 simpledateformat的format方法最終調(diào)用源碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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;
    }

注意calendar.settime(date);,calendar類是里面基本都是final修飾的,calendar是共享變量,并且這個共享變量沒有做線程安全控制。當(dāng)多個線程同時使用相同的simpledateformat對象【如用static修飾的simpledateformat,一般會封裝在工具類,復(fù)用】調(diào)用format方法時,多個線程會同時調(diào)用calendar.settime方法,可能一個線程剛設(shè)置好time值另外的一個線程馬上把設(shè)置的time值給修改了導(dǎo)致返回的格式化時間可能是錯誤的。

在多并發(fā)情況下使用simpledateformat需格外注意:

simpledateformat除了format方法是線程不安全以外,parse方法也是線程不安全的。parse方法實際調(diào)用alb.establish(calendar).gettime()方法來解析,alb.establish(calendar)方法里主要完成了

  • 重置日期對象cal的屬性值
  • 使用calb(calbuilder)中屬性設(shè)置cal
  • 返回設(shè)置好的cal對象

但是這三步不是原子操作

simpledateformat如何保證線程安全

  • 避免線程之間共享一個simpledateformat對象,每個線程使用時都創(chuàng)建一次simpledateformat對象 => 創(chuàng)建和銷毀對象的開銷大
  • 對使用format和parse方法的地方進行加鎖 => 線程阻塞性能差
  • 使用threadlocal保證每個線程最多只創(chuàng)建一次simpledateformat對象 => 較好的方法

date對時間處理比較麻煩,比如想獲取某年、某月、某星期,以及n天以后的時間,如果用date來處理的話真是太難了,你可能會說date類不是有g(shù)etyear、getmonth這些方法嗎,獲取年月日很easy,但都被棄用了啊

java8全新的日期和時間api

在使用java程序操作數(shù)據(jù)庫時,我們需要把數(shù)據(jù)庫類型與java類型映射起來。下表是數(shù)據(jù)庫類型與java新舊api的映射關(guān)系:

數(shù)據(jù)庫 對應(yīng)java類(舊) 對應(yīng)java類(新)
datetime java.util.date localdatetime
date   java.sql.date localdate
time  java.sql.time  localtime
timestamp  java.sql.timestamp  localdatetime

 localdate

只會獲取年月日

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//獲取當(dāng)前年月日
        localdate localdate = localdate.now();
        //構(gòu)造指定的年月日
        localdate localdate1 = localdate.of(2019, 9, 10);
 
        //獲取年、月、日、星期幾
        int year = localdate.getyear();
        int year1 = localdate.get(chronofield.year);
        month month = localdate.getmonth();
        int month1 = localdate.get(chronofield.month_of_year);
        int day = localdate.getdayofmonth();
        int day1 = localdate.get(chronofield.day_of_month);
        dayofweek dayofweek = localdate.getdayofweek();
        int dayofweek1 = localdate.get(chronofield.day_of_week);

localtime

只會獲取幾點幾分幾秒

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//創(chuàng)建localtime
        localtime localtime = localtime.of(13, 51, 10);
        localtime localtime1 = localtime.now();
 
        //獲取小時
        int hour = localtime.gethour();
        int hour1 = localtime.get(chronofield.hour_of_day);
        //獲取分
        int minute = localtime.getminute();
        int minute1 = localtime.get(chronofield.minute_of_hour);
        //獲取秒
        int second = localtime.getsecond();
        int second1 = localtime.get(chronofield.second_of_minute);

localdatetime

獲取年月日時分秒,等于localdate+localtime

?
1
2
3
4
5
6
7
8
9
10
11
12
//創(chuàng)建對象
        localdatetime localdatetime = localdatetime.now();
        localdatetime localdatetime1 = localdatetime.of(2019, month.september, 10, 14, 46, 56);
        //localdate+localtime-->localdatetime
        localdatetime localdatetime2 = localdatetime.of(localdate, localtime);
        localdatetime localdatetime3 = localdate.attime(localtime);
        localdatetime localdatetime4 = localtime.atdate(localdate);
 
        //獲取localdate
        localdate localdate2 = localdatetime.tolocaldate();
        //獲取localtime
        localtime localtime2 = localdatetime.tolocaltime();

zoneddatetime

localdatetime總是表示本地日期和時間,要表示一個帶時區(qū)的日期和時間,我們就需要zoneddatetime

可以簡單地把zoneddatetime理解成localdatetimezoneidzoneidjava.time引入的新的時區(qū)類,注意和舊的java.util.timezone區(qū)別。

創(chuàng)建一個zoneddatetime對象

?
1
2
3
4
// 默認時區(qū)
zoneddatetime zbj = zoneddatetime.now();
// 用指定時區(qū)獲取當(dāng)前時間
zoneddatetime zny = zoneddatetime.now(zoneid.of("america/new_york"));

結(jié)果:

2019-09-15t20:58:18.786182+08:00[asia/shanghai]
2019-09-15t08:58:18.788860-04:00[america/new_york]

另一種創(chuàng)建方式是通過給一個localdatetime附加一個zoneid,就可以變成zoneddatetime

?
1
2
3
localdatetime ldt = localdatetime.of(2019, 9, 15, 15, 16, 17);
zoneddatetime zbj = ldt.atzone(zoneid.systemdefault());
zoneddatetime zny = ldt.atzone(zoneid.of("america/new_york"));

時區(qū)轉(zhuǎn)換

要轉(zhuǎn)換時區(qū),首先我們需要有一個zoneddatetime對象,然后,通過withzonesameinstant()將關(guān)聯(lián)時區(qū)轉(zhuǎn)換到另一個時區(qū),轉(zhuǎn)換后日期和時間都會相應(yīng)調(diào)整。

?
1
2
3
zoneddatetime zbj = zoneddatetime.now(zoneid.of("asia/shanghai"));
// 轉(zhuǎn)換為紐約時間:
zoneddatetime zny = zbj.withzonesameinstant(zoneid.of("america/new_york"));

zoneddatetime仍然提供了plusdays()等加減操作。

要特別注意,時區(qū)轉(zhuǎn)換的時候,由于夏令時的存在,不同的日期轉(zhuǎn)換的結(jié)果很可能是不同的。這是北京時間9月15日的轉(zhuǎn)換結(jié)果:

2019-09-15t21:05:50.187697+08:00[asia/shanghai]
2019-09-15t09:05:50.187697-04:00[america/new_york]

這是北京時間11月15日的轉(zhuǎn)換結(jié)果:

2019-11-15t21:05:50.187697+08:00[asia/shanghai]
2019-11-15t08:05:50.187697-05:00[america/new_york]

兩次轉(zhuǎn)換后的紐約時間有1小時的夏令時時差。涉及到時區(qū)時,千萬不要自己計算時差,否則難以正確處理夏令時。有了zoneddatetime,將其轉(zhuǎn)換為本地時間就非常簡單:

?
1
2
zoneddatetime zdt = ...
localdatetime ldt = zdt.tolocaldatetime();

轉(zhuǎn)換為localdatetime時,直接丟棄了時區(qū)信息。

instant

獲取秒數(shù)或時間戳

?
1
2
3
4
5
6
7
//創(chuàng)建instant對象
        instant instant = instant.now();
        //獲取秒數(shù)
        long currentsecond = instant.getepochsecond();
        //獲取毫秒數(shù)
        long currentmilli = instant.toepochmilli();
        long l = system.currenttimemillis();

system.currenttimemillis()也可以獲取毫秒數(shù)。

日期計算

localdate、localtime、localdatetime、instant為不可變對象,修改這些對象對象會返回一個副本

增加、減少年數(shù)、月數(shù)、天數(shù)等,以localdatetime為例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//修改localdate、localtime、localdatetime、instant
        localdatetime localdatetime = localdatetime.of(2019, month.september, 10,
                14, 46, 56);
        //增加一年
        localdatetime = localdatetime.plusyears(1);
        localdatetime = localdatetime.plus(1, chronounit.years);
        //減少一個月
        localdatetime = localdatetime.minusmonths(1);
        localdatetime = localdatetime.minus(1, chronounit.months);
 
        //通過with修改某些值
        //修改年為2020
        localdatetime = localdatetime.withyear(2020);
        //修改為2022
        localdatetime = localdatetime.with(chronofield.year, 2022);
        //還可以修改月、日

有些時候想知道這個月的最后一天是幾號、下個周末是幾號,通過提供的時間和日期api可以很快得到答案

?
1
2
localdate localdate = localdate.now();
localdate localdate1 = localdate.with(temporaladjusters.firstdayofyear());

比如通過firstdayofyear()返回了當(dāng)前年的第一天日期,還有很多方法這里不在舉例說明

格式化時間

datetimeformatter默認提供了多種格式化方式,如果默認提供的不能滿足要求,可以通過datetimeformatter的ofpattern方法創(chuàng)建自定義格式化方式

?
1
2
3
4
5
6
localdate localdate = localdate.of(2019, 9, 10);
string s1 = localdate.format(datetimeformatter.basic_iso_date);
string s2 = localdate.format(datetimeformatter.iso_local_date);
//自定義格式化
datetimeformatter datetimeformatter = datetimeformatter.ofpattern("dd/mm/yyyy");
string s3 = localdate.format(datetimeformatter);

解析時間

和simpledateformat相比,datetimeformatter是線程安全的

?
1
2
localdate localdate1 = localdate.parse("20190910", datetimeformatter.basic_iso_date);
localdate localdate2 = localdate.parse("2019-09-10", datetimeformatter.iso_local_date);

datetimeformatter替代simpledateformat

使用舊的date對象時,我們用simpledateformat進行格式化顯示。使用新的localdatetimezonedlocaldatetime時,我們要進行格式化顯示,就要使用datetimeformatter

simpledateformat不同的是,datetimeformatter不但是不變對象,它還是線程安全的。因為simpledateformat不是線程安全的,使用的時候,只能在方法內(nèi)部創(chuàng)建新的局部變量。而datetimeformatter可以只創(chuàng)建一個實例,到處引用。

?
1
2
3
4
5
6
//構(gòu)造器1:傳入格式字符串
datetimeformatter formatter = datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss");
 
//構(gòu)造器2:傳入格式字符串和地區(qū)
datetimeformatter formatter = datetimeformatter.ofpattern("e, yyyy-mmmm-dd hh:mm:ss", locale.us);
datetimeformatter formatter = datetimeformatter.ofpattern("e, yyyy-mmmm-dd hh:mm:ss", locale.china);

datetimeformatter底層原理

datetimeformatter線程安全的?為什么?

源碼:

Java8新特性之線程安全日期類

很明顯,通過final修飾類,不可被繼承,final修飾變量,做成了不可變類,類似string,不僅線程安全而且高效。全局可以只有一個對象,多個線程引用。

format和parse線程安全替代

使用localdatetime的format和parse方法,傳入對應(yīng)的datetimeformatter對象參數(shù),實際也是調(diào)用datetimeformatter的format和parse方法,實現(xiàn)日期格式化和解析,是線程安全的。

datetimeformatter類解析localdatetime中的日期變量,轉(zhuǎn)成stringbuilder返回。localdatetime等新出的日期類全是final修飾的類,不能被繼承,且對應(yīng)的日期變量都是final修飾的,也就是不可變類。賦值一次后就不可變,不存在多線程數(shù)據(jù)問題。

Java8新特性之線程安全日期類

到此這篇關(guān)于java8新特性之線程安全日期類的文章就介紹到這了,更多相關(guān)java8線程安全日期類內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/qq_43409401/article/details/115696152

延伸 · 閱讀

精彩推薦
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程Java實現(xiàn)搶紅包功能

    Java實現(xiàn)搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7472021-02-04
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
主站蜘蛛池模板: 日本草草视频 | 天天舔天天操天天干 | 欧美三级做爰全过程 | 456老汉gay | 亚裔aⅴ艳星katsuni | 亚洲久草 | 国产综合亚洲专区在线 | 久久这里只精品热在线18 | 欧美高清乌克兰精品另类 | 欧美xxx000喷水 | 奇米网7777 | 四川一级毛片 | 久久热这里只有 精品 | 久久国产精品二区99 | 热99re久久精品精品免费 | 无遮挡h肉动漫高清在线 | 男女拍拍拍免费视频网站 | 美女漫画网 | 国产在线98福利播放视频免费 | 朝鲜美女免费一级毛片 | 成年人免费在线看 | 国产精品欧美韩国日本久久 | 国产一级毛片国语版 | 午夜伦伦电影理论片大片 | 好吊妞视频998www | 插得好爽 | v视界影院成片 | 果冻传媒天美传媒网址入口 | 亚洲天天做夜夜做天天欢 | 私人家庭影院5577 | 丝瓜黄瓜茄子西红柿秋葵榴莲 | 女同性互吃奶乳免费视频 | 国产免费丝袜调教视频 | 国产一区二区免费不卡在线播放 | 亚洲视频999 | 免费观看日本 | 亚洲色图中文字幕 | 情人梁家辉在线 | 欧美一级特黄特色大片 | 精品亚洲综合久久中文字幕 | 日韩高清在线免费看 |