2016-09-01 8 views
0

ファイルに書き込むメソッドが1つあります。私は、ファイルオブジェクトJavaで非静的メソッド変数(オブジェクト)を同期する方法

class MessageFile{ 

public static final String fileName="Main.html" 
@AutoWired 
AppConifg appconfig; 

public boolean writeToFile(String fileContent) throws Exception{ 

     String path = appConfig.getNewsPath() + File.separator + fileName; // getNewsPath is non-static method 
     final File alertFile= new File(path); 
     FileOutputStream out = null; 
     synchronized (alertFile) { 
      if (!alertFile.exists()) { 
       alertFile.createNewFile(); 
      } 
      try { 
       out = new FileOutputStream(alertFile, false); 
       out.write(fileContent.getBytes()); 
       out.flush(); 
      } finally { 
       if (out != null) { 
        out.close(); 
       } 
      } 
     } 
     return true; 
    } 


    } 

しかし、上記のコードは、このクラスの別のインスタンスなどのファイルオブジェクトの排他的ロックは、このクラスのロックを持っているし、ファイルに書き込むことができますロック取るwon`t同期させる必要があります。 だから私はこのケースをどのように処理したいですか? タイムスタンプを追加する一時ファイル名を作成する回避策が見つかったので(一時ファイル名は常に一意になります)、内容を書き込んだ後、最初に元のファイルを削除し、一時ファイルを元のファイル名に変更します。

+0

あなたの質問は不明です。排他ロックを使用できないのはなぜですか? – RealSkeptic

答えて

0

MessageFile.classがファイルにアクセスする唯一のオブジェクトであれば、同期を試みることができます。

0

メソッドが実行されるたびに新しいFileオブジェクト(alertFile)が作成されるため、ロックはメソッドが実行されるたびに異なるので何も実行しません。すべてのメソッド呼び出しでスタティックFileインスタンスを共有する必要があります。

pathは、メソッドが実行されるたびに異なることができれば、あなたはstatic Map<String, File>インスタンスを作成し、このようにそれを使用することができます。

  1. は、ファイルのパスを取得します。
  2. このパスに関連付けられているFileがない場合は、作成します。
  3. それ以外の場合は、マップから既存のFileインスタンスを回復してください。
  4. ロックとしてこのFileを使用して操作します。修正回答に基づいて

例:

class MessageFile{ 

    public static final String fileName="Main.html" 
    @AutoWired 
    AppConifg appconfig; 

    private static final Map<String, File> filesMap = new HashMap<>(); 

    public boolean writeToFile(String fileContent) throws Exception{ 

     String path = appConfig.getNewsPath() + File.separator + fileName; // getNewsPath is non-static method 

     final File alertFile; 
     synchronized(filesMap) { 
      if (filesMap.containsKey(path)) { 
       alertFile = filesMap.get(path); 
      } 
      else { 
       alertFile = new File(path); 
       filesMap.put(path, alertFile); 
      } 
     } 

     FileOutputStream out = null; 
     synchronized (alertFile) { 
      if (!alertFile.exists()) { 
       alertFile.createNewFile(); 
      } 
      try { 
       out = new FileOutputStream(alertFile, false); 
       out.write(fileContent.getBytes()); 
       out.flush(); 
      } finally { 
       if (out != null) { 
        out.close(); 
       } 
      } 
     } 
     return true; 
    } 


} 
+0

'File'オブジェクトはすべてのインスタンスに対して個別の' getNewsPath'の結果に基づいていることに注意してください。 – RealSkeptic

+0

"このパスに関連付けられた' File'がない場合、それを作成します。 - マルチスレッドコンテキストでは、競合条件が作成されます。私はあなたがコードを追加し、これをどのように解決するかを示すことをお勧めします。 – RealSkeptic

+0

コードサンプルが追加されました。 – Mac70

0

あなたはクラスMessageFile(それぞれのインスタンス間で共有されていないローカル変数alertFileに​​を使用しているので、あなたのプログラムは、ファイルの排他ロックを取得できません。オブジェクトには独自のalertFileがあります)。

1静的オブジェクトをいくつか作成して同期します(既にあるのでfileNameを使用することができます)。

2同じオブジェクト(コンストラクタで渡された)を指すすべてのオブジェクト内の参照を持ち、それを同期させます。

+0

初心者が変数とオブジェクトの違いを理解していないことを忘れないでください。あなたは、 "あなたはローカル変数に' synchronized'を使っていますが、 'foo'がローカル変数であるときに' synchronized(foo) 'を書いても何の問題もありません。同期は変数では動作しません。_オブジェクト_で動作します。本当の問題は、 'alertFile'変数が他のスレッドから知られていないオブジェクトを参照していることです。経験豊かな開発者にはこれは嫌な音だとわかっていますが、初心者にとっては、それは幻想と完全な、絶望的な混乱の違いです。 –

0

クラスレベルのオブジェクト、つまりMessageFile.classを同期させるか、静的同期メソッドwrtietofile()を使用します。一度に1つのスレッドだけがファイルに書き込むようにします。また、スレッドによってファイル全体にデータが書き込まれると、ロックが解除されることが保証されます。

関連する問題