2012-11-19 61 views
0

每次請求在我的網站頁面時,我記錄一些細節,像這樣一個服務電話:如何在Java中安全地操作文件線程?

logService.logPageRequest(session, request, contentId); 

此服務調用利用一個靜態的文件實用程序的(我自己)方法來執行實際的更新上文件。

public static void appendToTextFile(String string, String fileRootDirectory, String subdirectory, String filename, boolean startOnNewLine) throws Exception { 
    // code irrelevant to the question removed 

    String filePath=fileDirectory+"/"+filename; 
    File file=new File(filePath); 
    if(file.exists()) { 
     FileWriter out = new FileWriter(filePath, true); 
     if(startOnNewLine) { 
      out.write("\r\n"); 
     } 
     out.write(string); 
     out.close(); 
    } else { 
     FileWriter out = new FileWriter(filePath); 
     out.write(string); 
     out.close(); 
} 

每隔一段時間(假設每15分鐘計劃一次),我執行另一個服務,重命名此文件並開始處理它。

我想了解如何確保兩個併發寫入都是安全的,並且在寫入過程中不會執行重命名。我想答案會是某種形式的同步。

回答

2

這兩項服務需要共享一個同步對象:它可以是任何東西(甚至new byte[1]),但它必須是一個相同的情況下,傳遞到你的「服務」。每當有關鍵部分,這意味着它要在共享資源操作守則的一部分,它需要被包裹在

synchronized(theInstanceOfSynchronizationObject) { 
    // ... your code for critical section 
} 

好鎖定的規則是確定性什麼都知道你鎖定,什麼是共享資源。什麼會殺死你(並引入死鎖)是隨機添加同步塊以期「解決」。在您的具體的例子,它是最有可能在file行動:正義行動,而不是文件名字符串的操作,既不File的實例:你可以有很多File對象指向同文件在磁盤上,它不是一個關鍵操作,只要它不接觸磁盤。所以,我要說

File file=new File(filePath); 
synchronized(theInstanceOfSynchronizationObject) { 
    if(file.exists()) { 
    } else { 
    } 
} 

同樣,保護File行動在你的其他服務。請記住,它不是File對象,而是文件本身

+0

Pavel,theInstanceOfSynchronizationObject會是什麼?某種類型的公共靜態對象屬性?你爲這些創建了一個單獨的專門課程?性能如何?每次我們寫入文件,我們都需要同步。我想知道這在實踐中意味着什麼。有些人選擇寫入隊列而不是直接寫入文件。你有沒有做過這些,並且足夠了解選擇有意義的東西? – jacekn

+0

public static屬性是最簡單的方法,雖然有點髒。 Cleaner是將一個特殊的實例傳遞給服務(也許是通過構造函數)。專用類不是必需的,你只需要使用Object(任何對象)能力來充當鎖。雖然鎖定確實需要一些時間,但它仍然比訪問磁盤文件快幾個數量級。所以我不會考慮它的性能問題。 –