Javaプロセス間ファイルロックFileLockの詳細

4093 ワード

最近は2つのプロセスで同じファイルを操作する必要があります.ちょうどJavaはファイルロックFileLockクラスを提供しています.このクラスを利用して、異なるプログラム(JVM)の同じファイルへの同時アクセスを制御し、プロセス間のファイル同期操作を実現することができます.
FileLockはjava 1.4バージョン後に現れたクラスで、1つの書き込み可能なファイル(w)にロックをかけることで、同時に1つのプロセスだけがファイルのロックを受け取ることができることを保証し、このプロセスはファイルにアクセスすることができる.ロックが取れない他のプロセスは、保留中に待機するか、他のことをするかを選択します.このようなメカニズムは、多くのプロセスがファイルに順次アクセスできることを保証します.ファイルロックのこの性質を利用することができ、いくつかのシーンでは、あるファイルを操作する必要はありませんが、FileLockによって同時制御を行い、プロセスの順序実行を保証し、データエラーを避けることができます.
 “Locks are associated with files, not channels. Use locks to coordinate with external processes, not between threads in the same JVM.”
1.概念
  • 共有ロック:読み取り操作を共有しますが、書き込みは1つしかできません(読み取りは同時にできますが、書き込みはできません).共有ロックは、他の実行中のプログラムが重複する排他ロックを取得することを防止しますが、重複する共有ロックを取得することを許可します.
  • 排他ロック:1つの読み取りまたは1つの書き込みのみ(読み取りと書き込みは同時にできません).排他ロックは、他のプログラムが任意のタイプのロックを取得することを防止します.
  • 2. FileLock FileChannel.lock(long position, long size, boolean shared)
  • sharedの意味:共有ロックを使用するかどうか、共有ロックをサポートしていないオペレーティングシステムの中には、自動的に共有ロックを排他ロックに変更します.取得されたロックのタイプは、isShared()メソッドを呼び出すことによって検出することができる.

  • 3.lock()とtryLock()の違い:
  • lock()ブロックの方法では、ロック範囲はファイルの増加に伴って増加することができる.非参照lock()はデフォルトで独占ロックです.ロック(0 L,Long.MAX_VALUE,true)は共有ロックです.
  • tryLock()は非ブロックである、ロックが得られない場合nullに戻る.

  • 4.FileLockのライフサイクル:FileLockを呼び出す.release()、またはChannel.close()またはJVMオフ
    5.FileLockはスレッドが安全です
    6.注意事項:
  • 同じプロセス内では、ファイルロックが解放されないまで、再取得できません.すなわちrelease()メソッドが呼び出される前にlock()またはtryLock()しかできない.
  • ファイルロックの効果はオペレーティングシステムに関連しています.一部のシステムでは、Javaのプロセスがファイルロックを取得すると、オペレーティングシステムは他のプロセスがファイルを操作できないことを保証します.他のオペレーティングシステムのファイルロックは、プロセス反発の効果を持つためには、他のプロセスもAPIに規定されているようにファイルロックを申請したり検出したりしなければならないという意味で、プロセス反発の機能を果たすことはできません.したがって、ドキュメントでは、すべてのシステムを質問式システムとして処理することをお勧めします.これにより、プログラムがより安全で移植しやすくなります.
  • デッドロックを回避する方法:重要なデータを読み書きするときにロックをかけ、操作が完了した後にロックを解除する.必要なすべてのリソースを一度に申請し、申請が成功しない場合に申請したリソースを放棄します.

  • 7.サンプルコード:
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    import java.util.Date;
    
    public class FileLockTest {
    
        public static void main(String[] args){
            FileChannel channel = null;
            FileLock lock = null;
            try {
                //1.                    NonWritableChannelException  
                //2.   lock()      ,   NonReadableChannelException  ,         
                //3.   lock()    ,           ,     ,              ,        NonWritableChannelException  
                channel = new FileOutputStream("logfile.txt",true).getChannel();
                RandomAccessFile raf = new RandomAccessFile("logfile.txt","rw");
    
                //            
                raf.seek(raf.length());
                channel = raf.getChannel();
    
                //      :lock(),     ,        ,        
                lock = channel.lock();//  lock()    
                //lock = channel.lock(0L, Long.MAX_VALUE, true);//  lock()    ,        
    
                //      :trylock(),      ,        ,tryLock()   null 
                //do {
                //  lock = channel.tryLock();
                //} while (null == lock);
    
                //    
                ByteBuffer sendBuffer=ByteBuffer.wrap((new Date()+"   
    ").getBytes()); channel.write(sendBuffer); Thread.sleep(5000); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock != null) { try { lock.release(); lock = null; } catch (IOException e) { e.printStackTrace(); } } if (channel != null) { try { channel.close(); channel = null; } catch (IOException e) { e.printStackTrace(); } } } } }