2012-11-19 31 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(任何对象)能力来充当锁。虽然锁定确实需要一些时间,但它仍然比访问磁盘文件快几个数量级。所以我不会考虑它的性能问题。 –