国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

JDK的一個(gè)Bug,監(jiān)聽(tīng)文件變更要小心了

開(kāi)發(fā) 前端
本文實(shí)踐了一個(gè)很常見(jiàn)的功能,起初采用很符合常規(guī)思路的方案來(lái)解決,結(jié)果恰好碰到了JDK的Bug,只好變更策略來(lái)實(shí)現(xiàn)。

背景

在某些業(yè)務(wù)場(chǎng)景下,我們需要自己實(shí)現(xiàn)文件內(nèi)容變更監(jiān)聽(tīng)的功能,比如:監(jiān)聽(tīng)某個(gè)文件是否發(fā)生變更,當(dāng)變更時(shí)重新加載文件的內(nèi)容。

看似比較簡(jiǎn)單的一個(gè)功能,但如果在某些JDK版本下,可能會(huì)出現(xiàn)意想不到的Bug。

本篇文章就帶大家簡(jiǎn)單實(shí)現(xiàn)一個(gè)對(duì)應(yīng)的功能,并分析一下對(duì)應(yīng)的Bug和優(yōu)缺點(diǎn)。

初步實(shí)現(xiàn)思路

監(jiān)聽(tīng)文件變動(dòng)并讀取文件,簡(jiǎn)單的思路如下:

  • 單起一個(gè)線程,定時(shí)獲取文件最后更新的時(shí)間戳(單位:毫秒);
  • 對(duì)比上一次的時(shí)間戳,如果不一致,則說(shuō)明文件被改動(dòng),則重新進(jìn)行加載;

這里寫一個(gè)簡(jiǎn)單功能實(shí)現(xiàn)(不包含定時(shí)任務(wù)部分)的demo:

public class FileWatchDemo {

/**
* 上次更新時(shí)間
*/
public static long LAST_TIME = 0L;

public static void main(String[] args) throws IOException {

String fileName = "/Users/zzs/temp/1.txt";
// 創(chuàng)建文件,僅為實(shí)例,實(shí)踐中由其他程序觸發(fā)文件的變更
createFile(fileName);

// 執(zhí)行2次
for (int i = 0; i < 2; i++) {
long timestamp = readLastModified(fileName);
if (timestamp != LAST_TIME) {
System.out.println("文件已被更新:" + timestamp);
LAST_TIME = timestamp;
// 重新加載,文件內(nèi)容
} else {
System.out.println("文件未更新");
}
}
}

public static void createFile(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
boolean result = file.createNewFile();
System.out.println("創(chuàng)建文件:" + result);
}
}

public static long readLastModified(String fileName) {
File file = new File(fileName);
return file.lastModified();
}
}

在上述代碼中,先創(chuàng)建一個(gè)文件(方便測(cè)試),然后兩次讀取文件的修改時(shí)間,并用LAST_TIME記錄上次修改時(shí)間。如果文件的最新更改時(shí)間與上一次不一致,則更新修改時(shí)間,并進(jìn)行業(yè)務(wù)處理。

示例代碼中for循環(huán)兩次,便是為了演示變更與不變更的兩種情況。執(zhí)行程序,打印日志如下:

文件已被更新:1653557504000
文件未更新

執(zhí)行結(jié)果符合預(yù)期。

這種解決方案很明顯有兩個(gè)缺點(diǎn):

  • 無(wú)法實(shí)時(shí)感知文件的變動(dòng),程序輪訓(xùn)畢竟有一個(gè)時(shí)間差;
  • lastModified返回的時(shí)間單位是毫秒,如果同一毫秒內(nèi)容出現(xiàn)兩次改動(dòng),而定時(shí)任務(wù)查詢時(shí)恰好落在兩次變動(dòng)之間,則后一次變動(dòng)則無(wú)法被感知到。

第一個(gè)缺點(diǎn),對(duì)業(yè)務(wù)的影響不大;第二個(gè)缺點(diǎn)的概率比較小,可以忽略不計(jì);

JDK的Bug登場(chǎng)

上面的代碼實(shí)現(xiàn),正常情況下是沒(méi)什么問(wèn)題的,但如果你使用的Java版本為8或9時(shí),則可能出現(xiàn)意想不到的Bug,這是由JDK本身的Bug導(dǎo)致的。

編號(hào)為JDK-8177809的Bug是這樣描述的:

Bug地址為:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8177809

這個(gè)Bug的基本描述就是:在Java8和9的某些版本下,lastModified方法返回時(shí)間戳并不是毫秒,而是秒,也就是說(shuō)返回結(jié)果的后三位始終為0。

我們來(lái)寫一個(gè)程序驗(yàn)證一下:

public class FileReadDemo {

public static void main(String[] args) throws IOException, InterruptedException {

String fileName = "/Users/zzs/temp/1.txt";
// 創(chuàng)建文件
createFile(fileName);

for (int i = 0; i < 10; i++) {
// 向文件內(nèi)寫入數(shù)據(jù)
writeToFile(fileName);
// 讀取文件修改時(shí)間
long timestamp = readLastModified(fileName);
System.out.println("文件修改時(shí)間:" + timestamp);
// 睡眠100ms
Thread.sleep(100);
}
}

public static void createFile(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
boolean result = file.createNewFile();
System.out.println("創(chuàng)建文件:" + result);
}
}

public static void writeToFile(String fileName) throws IOException {
FileWriter fileWriter = new FileWriter(fileName);
// 寫入隨機(jī)數(shù)字
fileWriter.write(new Random(1000).nextInt());
fileWriter.close();
}

public static long readLastModified(String fileName) {
File file = new File(fileName);
return file.lastModified();
}
}

在上述代碼中,先創(chuàng)建一個(gè)文件,然后在for循環(huán)中不停的向文件寫入內(nèi)容,并讀取修改時(shí)間。每次操作睡眠100ms。這樣,同一秒就可以多次寫文件和讀修改時(shí)間。

執(zhí)行結(jié)果如下:

文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558619000
文件修改時(shí)間:1653558620000
文件修改時(shí)間:1653558620000
文件修改時(shí)間:1653558620000
文件修改時(shí)間:1653558620000

修改了10次文件的內(nèi)容,只感知到了2次。JDK的這個(gè)bug讓這種實(shí)現(xiàn)方式的第2個(gè)缺點(diǎn)無(wú)限放大了,同一秒發(fā)生變更的概率可比同一毫秒發(fā)生的概率要大太多了。

PS:在官方Bug描述中提到可以通過(guò)Files.getLastModifiedTime來(lái)實(shí)現(xiàn)獲取時(shí)間戳,但筆者驗(yàn)證的結(jié)果是依舊無(wú)效,可能不同版本有不同的表現(xiàn)吧。

更新解決方案

Java 8目前是主流版本,不可能因?yàn)镴DK的該bug就換JDK吧。所以,我們要通過(guò)其他方式來(lái)實(shí)現(xiàn)這個(gè)業(yè)務(wù)功能,那就是新增一個(gè)用來(lái)記錄文件版本(version)的文件(或其他存儲(chǔ)方式)。這個(gè)version的值,可在寫文件時(shí)按照遞增生成版本號(hào),也可以通過(guò)對(duì)文件的內(nèi)容做MD5計(jì)算獲得。

如果能保證版本順序生成,使用時(shí)只需讀取版本文件中的值進(jìn)行比對(duì)即可,如果變更則重新加載,如果未變更則不做處理。

如果使用MD5的形式,則需考慮MD5算法的性能,以及MD5結(jié)果的碰撞(概率很小,可以忽略)。

下面以版本的形式來(lái)展示一下demo:

public class FileReadVersionDemo {

public static int version = 0;

public static void main(String[] args) throws IOException, InterruptedException {

String fileName = "/Users/zzs/temp/1.txt";
String versionName = "/Users/zzs/temp/version.txt";
// 創(chuàng)建文件
createFile(fileName);
createFile(versionName);

for (int i = 1; i < 10; i++) {
// 向文件內(nèi)寫入數(shù)據(jù)
writeToFile(fileName);
// 同時(shí)寫入版本
writeToFile(versionName, i);
// 監(jiān)聽(tīng)器讀取文件版本
int fileVersion = Integer.parseInt(readOneLineFromFile(versionName));
if (version == fileVersion) {
System.out.println("版本未變更");
} else {
System.out.println("版本已變化,進(jìn)行業(yè)務(wù)處理");
}
// 睡眠100ms
Thread.sleep(100);
}
}

public static void createFile(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
boolean result = file.createNewFile();
System.out.println("創(chuàng)建文件:" + result);
}
}

public static void writeToFile(String fileName) throws IOException {
writeToFile(fileName, new Random(1000).nextInt());
}

public static void writeToFile(String fileName, int version) throws IOException {
FileWriter fileWriter = new FileWriter(fileName);
fileWriter.write(version +"");
fileWriter.close();
}

public static String readOneLineFromFile(String fileName) {
File file = new File(fileName);
String tempString = null;
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
//一次讀一行,讀入null時(shí)文件結(jié)束
tempString = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return tempString;
}
}

執(zhí)行上述代碼,打印日志如下:

版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理
版本已變化,進(jìn)行業(yè)務(wù)處理

可以看到,每次文件變更都能夠感知到。當(dāng)然,上述代碼只是示例,在使用的過(guò)程中還是需要更多地完善邏輯。

小結(jié)

本文實(shí)踐了一個(gè)很常見(jiàn)的功能,起初采用很符合常規(guī)思路的方案來(lái)解決,結(jié)果恰好碰到了JDK的Bug,只好變更策略來(lái)實(shí)現(xiàn)。當(dāng)然,如果業(yè)務(wù)環(huán)境中已經(jīng)存在了一些基礎(chǔ)的中間件還有更多解決方案。

而通過(guò)本篇文章我們學(xué)到了JDK Bug導(dǎo)致的連鎖反應(yīng),同時(shí)也見(jiàn)證了:實(shí)踐見(jiàn)真知。很多技術(shù)方案是否可行,還是需要經(jīng)得起實(shí)踐的考驗(yàn)才行。趕快檢查一下你的代碼實(shí)現(xiàn),是否命中該Bug?

責(zé)任編輯:武曉燕 來(lái)源: 程序新視界
相關(guān)推薦

2022-05-16 08:42:26

Pandasbug

2021-09-13 08:41:52

職場(chǎng)互聯(lián)網(wǎng)自閉

2020-01-10 09:20:03

手機(jī)ISOJDK

2018-06-20 15:50:38

JDK9JVMJDK10

2020-09-29 07:44:20

跨域前后端分離插件

2025-02-13 07:00:00

Dubbo-goJava服務(wù)端

2009-09-14 17:08:02

WebFormView

2021-04-22 07:47:47

JavaJDKMYSQL

2022-11-30 09:18:51

JavaMyBatisMQ

2022-05-10 12:20:04

JDKversion故障

2021-10-08 07:50:57

軟件設(shè)計(jì)程序

2011-07-29 16:55:44

Java 7

2017-10-10 15:14:23

BUGiOS 11蘋果

2015-01-23 10:04:56

bug程序員

2016-09-28 14:00:56

2023-01-26 11:43:03

線程池CPUJava

2024-10-25 12:38:27

2023-06-20 08:25:53

NESTED源碼mybatis

2014-12-17 09:40:22

dockerLinuxPaaS

2024-04-22 00:00:01

Redis集群
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

888久久久| 国产一级在线| 加勒比av一区二区| 2023欧美最顶级a∨艳星| 欧美精品一区二区三区蜜桃 | 五月天婷婷综合社区| 极品束缚调教一区二区网站| 亚洲精品在线播放| 国产综合久久久久久鬼色 | 忘忧草在线www成人影院| 日韩伦理一区| 国产白丝网站精品污在线入口| 亚洲国产精品久久| 欧美精品一区二区三区在线四季 | 亚洲aⅴ天堂av在线电影软件| а√中文在线8| 91老师国产黑色丝袜在线| 国产成+人+综合+亚洲欧美丁香花| 超碰超碰97| proumb性欧美在线观看| 欧美在线一区二区三区四区| 蜜桃国内精品久久久久软件9| 一本大道久久加勒比香蕉| 懂色av一区| 欧美嫩在线观看| а√天堂官网中文在线| 777久久久精品| 成人国产电影在线观看| 亚洲福利精品在线| 亚洲伊人伊成久久人综合网| 久久精品视频免费播放| 高清精品xnxxcom| 国产热re99久久6国产精品| 欧美一区影院| 欧美日韩亚洲国产成人| 亚洲国产成人在线| 小小水蜜桃在线观看| 亚洲激情第一页| 欧美黄视频在线观看| 91九色精品视频| 蜜桃免费网站一区二区三区| 国产精品亚洲αv天堂无码| 亚洲成av人片观看| tube8在线hd| 国产精品高潮呻吟久久av黑人| 影音先锋久久久| 性刺激的欧美三级视频| 3d动漫精品啪啪1区2区免费| 日韩在线激情| 国产一区二区不卡视频| 久久久91精品国产一区二区精品| 欧美在线一卡| 久久精品电影网站| 亚洲高清在线| 免费高清成人| 中文字幕日韩欧美在线| 午夜宅男久久久| 粉嫩tv在线播放| 九九精品视频在线观看| 久久精品卡一| 日本国产在线| 国产精品www色诱视频| 成人黄色小视频在线观看| 精品一二三区视频| 欧美最顶级的aⅴ艳星| 国产99精品国产| 日本欧美电影在线观看| 国产欧美日韩免费看aⅴ视频| 99国产一区二区三精品乱码| 大桥未久在线播放| 久久久国产精品一区二区三区| 亚洲一区二区精品3399| 国产精品久av福利在线观看| 999在线观看视频| 国产亚洲精品va在线观看| 日韩av电影免费观看高清完整版| 亚洲人成电影| 成人黄色免费在线观看| 亚洲自拍欧美精品| 欧美亚洲精品在线| 久热久精久品这里在线观看 | 日韩中文字幕免费| 极品少妇xxxx精品少妇| 午夜影院在线观看国产主播| 久久综合色一本| 3d动漫精品啪啪一区二区竹菊| 国产一区二区三区久久久久久久久| 色哟哟免费在线观看 | 国产精品系列在线观看| 日本美女久久| 国产91色在线观看| 欧美一级片免费在线| 亚洲国产aⅴ成人精品无吗| 精品国产一区二区三区小蝌蚪| 奇门遁甲1982国语版免费观看高清| 亚洲国产岛国毛片在线| 天天综合亚洲| aaa大片在线观看| 久久国产亚洲精品无码| 欧洲成人性视频| 精品国产伦一区二区三区观看方式 | 欧美日韩综合久久| xxx成人少妇69| 亚洲图片欧美激情| 日韩一级大片| a屁视频一区二区三区四区| 免费99热在线观看| 欧美日韩精品久久| 久久久久久欧美| 在线综合亚洲欧美在线视频| 国产91精品露脸国语对白| 久久免费大视频| 日本精品在线中文字幕| 在线观看av网站永久| 一区二区在线观看网站| 日韩av男人的天堂| 一区二区三区黄色| 欧美日韩国产综合久久| 国产精品国产三级国产| 国产一区二区精品久久91| 欧美午夜不卡影院在线观看完整版免费| 黄色成人在线观看网站| 青青色在线视频| 国产福利电影在线观看| 我的公把我弄高潮了视频| 精品免费二区三区三区高中清不卡| 国内精品免费午夜毛片| 日韩一区二区av| 亚洲精品之草原avav久久| 日韩手机在线导航| 欧美精品1区2区3区| 色94色欧美sute亚洲13| 亚洲国产精品一区二区尤物区| 国产欧美在线观看一区| 91免费观看在线| 国产在线精品一区在线观看麻豆| 亚洲免费激情| 国产精品久久777777毛茸茸| 国产精品jizz在线观看美国| 久久精品不卡| 午夜日韩福利| 亚洲天堂偷拍| 免费在线亚洲欧美| 蜜桃视频一区| 精品一区二区三区香蕉蜜桃 | 91精品国产一区二区三区香蕉| 欧美性猛交xxxxxx富婆| 欧洲国内综合视频| 日韩欧美www| 亚洲午夜久久久久久久| 欧美成人激情视频免费观看| 欧美激情精品久久久久久免费印度| 久久亚洲精品一区二区| 97久久国产精品| 91欧美激情另类亚洲| 国产一区二区三区无遮挡| 久久综合一区二区三区| 亚洲欧美日韩不卡| 男人揉女人奶房视频60分| 97秋霞电影网| 黄色网在线看| 动漫一区二区三区| 中文字幕免费一区二区三区| 蜜桃精品视频在线| 综合色天天鬼久久鬼色| 欧美性生活一区| 欧美成人国产va精品日本一级| 国产在线久久久| 日韩黄色片在线| 亚洲成人影院在线观看| 综合日韩av| 欧美一区二区三区久久精品| 国产高清久久久| 欧美视频中文字幕| 久久久久久久久久久人体| 久久久www免费人成黑人精品| 99久久激情视频| 黄色av电影在线播放| 成人精品电影| 久久婷婷国产综合精品青草| 欧美日韩激情一区二区三区| 久久久久女教师免费一区| 91香蕉视频网址| 亚亚洲欧洲精品| 蜜臀91精品国产高清在线观看| 国产一区二区调教| 91精品国产一区二区三区香蕉| 97婷婷涩涩精品一区| 日韩极品视频在线观看| eeuss影院在线播放| 中文字幕亚洲精品乱码| 亚洲欧美激情视频在线观看一区二区三区| 日韩精品高清在线| 亚洲一区二区在线免费观看| 黄av在线播放| 99国产精品久久久久久久成人热| 亚洲sss视频在线视频| 热久久99这里有精品| av黄色免费在线| 久久国产精品成人免费观看的软件|