亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

這是同步代碼塊的安全方法嗎?

這是同步代碼塊的安全方法嗎?

眼眸繁星 2023-06-08 19:28:57
在我們的應用程序中,有一段代碼不斷運行以讀取和調整文件。只是為了讓您了解正在發生的事情:public void run() {    try {        while(true) { //Yeah, I know...            Path currentFileName = getNextFile();            String string = readFile(currentFileName);            Files.deleteFile(currentFileName);            string = string.replaceAll("Hello", "Blarg");            writeFile(currentFileName);        }    } catch (Exception e) {        System.err.println("It's all ogre now.");        e.printStackTrace(System.err);    }}我們代碼中的其他地方有一個方法,它可能(但通常)不在與上述代碼相同的線程上運行,我們用它來退出應用程序。private void shutdown() {    if(fileReader != null)        fileReader = null;    System.exit(0); //Don't blame me, I didn't write this code}很明顯,此代碼中存在潛在的競爭條件,如果在shutdown()檢索文件和寫回文件之間調用 if ,則可能會導致文件完全丟失。顯然,這是不受歡迎的行為。這段代碼有上千個問題(超出了我在這里展示的范圍),但我需要解決的主要問題是處理文件可以中途中斷而沒有追索權的不良行為。我提出的解決方案涉及簡單地將 while 循環包裝在一個塊中,并在調用synchronized周圍放置一個塊。System.exitshutdown所以我更改后的代碼如下所示:private Object monitor = new Object();public void run() {    try {        while(true) {            synchronized(monitor) {                Path currentFileName = getNextFile();                String string = readFile(currentFileName);                Files.deleteFile(currentFileName);                string = string.replaceAll("Hello", "Blarg");                writeFile(currentFileName);            }        }    } catch (Exception e) {        System.err.println("It's all ogre now.");        e.printStackTrace(System.err);    }}private void shutdown() {    synchronized(monitor) {        if(fileReader != null)            fileReader = null;         System.exit(0);    }}我主要擔心的是System.exit(0);電話,我不確定電話幕后的總體行為。System.exit是否存在將釋放鎖的副作用的風險monitor,從而導致循環內容在導致 JVM 停止run之前被部分執行的風險?System.exit還是這段代碼會保證執行過程永遠不會在處理單個文件時嘗試中途關閉?注意:在一些紙上談兵的程序員介入替代方案之前,我想指出,我在這里放置的是大約 4000 行代碼的截斷版本,所有代碼都隱藏在一個類中。是的,這太可怕了。是的,這讓我后悔我選擇的職業。我不是在這里尋找這個問題的替代解決方案,我只是想確定這個特定的解決方案是否有效,或者是否存在一些嚴重的缺陷會阻止它像我預期的那樣工作。
查看完整描述

4 回答

?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

還是這段代碼會保證執行過程永遠不會在處理單個文件時嘗試中途關閉?

此代碼保證此處啟動的關閉不會在處理單個文件的過程中發生。也許很明顯,您代碼中的其他地方可以調用System.exit,而您對此沒有任何保護。

您可能需要考慮防止System.exit被調用,然后讓您的代碼正常關閉(即通過方法的正常完成main)。


查看完整回答
反對 回復 2023-06-08
?
翻閱古今

TA貢獻1780條經驗 獲得超5個贊

萬一你真的有多個線程調用不同的方法,synchronized這樣使用實際上是一個聰明的主意,因為它處理了“多線程”的事情。


您可以考慮縮小第一個塊的范圍:


Path currentFileName = getNextFile();

String string = readFile(currentFileName);

synchronized(monitor) {

單獨讀取文件應該不是問題。(當然,除非您此處的代碼必須保證由 返回的 PathgetNextFile()得到完全處理)。


查看完整回答
反對 回復 2023-06-08
?
慕無忌1623718

TA貢獻1744條經驗 獲得超4個贊

如果代碼在synchronized塊中執行并且塊在同一個對象上同步,并且synchronized循環中塊中調用的方法while完全在與其調用者相同的線程上運行,則不存在文件相關進程被中斷的風險通過調用System.exit. _

這就是說,它看起來確實像是一個有爭議的補丁,只是稍微改進了有爭議的代碼。

可能還存在更具體的饑餓風險,因為顯示的 while 循環似乎盡可能快地向這些文件操作發送垃圾郵件,因此在退出時嘗試獲取鎖可能不會成功。

探索的一般方向是將無限while循環轉換為ScheduledExecutorServiceRunnable,使用自己的監視器執行每 x 時間量以防止對相同文件的重疊操作,并在shutdown調用該方法時優雅地終止它。


查看完整回答
反對 回復 2023-06-08
?
繁星淼淼

TA貢獻1775條經驗 獲得超11個贊

您可以使用關閉掛鉤。來自 javadocs:

關閉掛鉤只是一個已初始化但未啟動的線程。當虛擬機開始其關閉序列時,它將以某種未指定的順序啟動所有已注冊的關閉掛鉤,并讓它們同時運行。

由此,您可以從您的文件類中提供一個關閉掛鉤,如下所示:

public Thread getShutdownHook() {

? ? return new Thread(() -> {

? ? ? ? synchronized (monitor) {

? ? ? ? ? ? // gracefully handle the file object

? ? ? ? }

? ? });

}

這將在調用時調用Runtime.getRuntime().exit()(由 調用System.exit())。由于它也在監視器對象上同步,如果其他線程正在使用該文件,關閉掛鉤將阻塞直到它空閑為止。


查看完整回答
反對 回復 2023-06-08
  • 4 回答
  • 0 關注
  • 204 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號