zoukankan      html  css  js  c++  java
  • [转载] 文件锁(Filelock)与锁定映射文件部分内容

    转载自http://jiangzhengjun.iteye.com/blog/517677

    文件锁

    JDK 1.4引入了文件加锁机制,允许我们同步访问一个共享文件,不过,竞争同一文件的两个线程有可能在不同的java虚拟机上,或者一个是java线程,另一个是操作系统中其他的某个线程,但文件锁对其他线程或其他操作系统进程都是可见的,因为java的文件加锁直接映射到了本地操作系统的加锁机制。
    注,这里讲的锁是指锁定其他应用程序,而不是锁定同一虚拟机里访问的同一文件的其他线程 。如果在同一虚拟机两次锁定同一文件或某文件里的同一区域,tryLock与lock则会抛出OverlappingFileLockException异常。
    要想获取整个文件的锁,可以用FileChannel的tryLock( )或lock( )方法。(SocketChannel,DatagramChannel,以及 ServerSocketChannel是不需要锁的,因为它们是从单进程实体继承而来;一般来说,你是不会让两个进程去共享一个网络socket的。tryLock( ) 是非阻塞的,它会试着去获取这个锁,但是如果得不到(其它进程已经以独占方式得到这个锁了),那它就直接返回;而lock( )是阻塞的,如果得不到锁,它会在一直处于阻塞状态,除非它得到了锁,或者你打断了调用它的线程,或者关闭了它要lock()的channel,否则它是不会返回的。最后用FileLock.release( )释放锁。 还可以像这样锁住文件的某一部分 tryLock(long position, long size, boolean shared) 或者 lock(long position, long size, boolean shared) 这个方法能锁住文件的某个区域(size - position)。其中第三个参数表示是否是共享锁。
    虽然在修改文件的过程中,无参数的lock( )和tryLock( )方法的锁定范围会随文件大小的变化,带参数的方法却不行。如果你锁住了position到position+size这段范围,而文件的长度又增加了,那么position+size后面是不加锁的。而无参数的lock方法则会锁定整个文件,不管它变不变长。
    锁是独占的还是共享的,这要由操作系统来决定。如果操作系统不支持共享锁,而程序又申请了一个共享锁,那么它会返回一个独占锁。你可以用FileLock.isShared( )来查询锁的类型(共享还是独占)。
    在写文件时才能锁定,如果对一个只读文件通道进行锁定操作时,会抛NonWritableChannelException异常,即new FileInputStream("data2.txt").getChannel().tryLock();时就会抛异常。
    另外锁定写文件通道new FileOutputStream("data2.txt").getChannel().tryLock();时,它会清掉原文件中的内容,所以当文件中有内容时最好使用 new FileOutputStream("data2.txt",true).getChannel().tryLock(); 以追加方式打开写文件通道。或者使用RandomAccessFile类来创建文件通道然后锁定 new RandomAccessFile("data2.txt","rw").getChannel().tryLock(); ,这样它不会破坏锁定的文件的内容。
    最后在使用tryLock()获取锁时, 有可能获取不到,这时就会为null,我们需能对此做相应处理。以下是简单的销实例:

    Java代码 复制代码 收藏代码
    1. import java.io.FileOutputStream;  
    2. import java.nio.channels.FileLock;  
    3.   
    4. public class FileLocking {  
    5.     public static void main(String[] args) throws Exception {  
    6.         FileOutputStream fos = new FileOutputStream("file.txt");  
    7.         //获取文件锁 FileLock 对象  
    8.         FileLock fl = fos.getChannel().tryLock();  
    9.         //tryLock是尝试获取锁,有可能为空,所以要判断  
    10.         if (fl != null) {  
    11.             System.out.println("Locked File");  
    12.             Thread.sleep(100);  
    13.             fl.release();//释放锁  
    14.             System.out.println("Released Lock");  
    15.         }  
    16.         fos.close();  
    17.     }  
    18. }  
    import java.io.FileOutputStream;
    import java.nio.channels.FileLock;
    
    public class FileLocking {
    	public static void main(String[] args) throws Exception {
    		FileOutputStream fos = new FileOutputStream("file.txt");
    		//获取文件锁 FileLock 对象
    		FileLock fl = fos.getChannel().tryLock();
    		//tryLock是尝试获取锁,有可能为空,所以要判断
    		if (fl != null) {
    			System.out.println("Locked File");
    			Thread.sleep(100);
    			fl.release();//释放锁
    			System.out.println("Released Lock");
    		}
    		fos.close();
    	}
    }

    锁定映射文件中的部分内容

    文件映射通常用于很大的文件,因此我们可能需要对文件操作的部分进行加锁,以便其他进程可以修改文件中未被加锁的部分。

    Java代码 复制代码 收藏代码
    1. import java.io.IOException;  
    2. import java.io.RandomAccessFile;  
    3. import java.nio.ByteBuffer;  
    4. import java.nio.MappedByteBuffer;  
    5. import java.nio.channels.FileChannel;  
    6. import java.nio.channels.FileLock;  
    7.   
    8. public class LockingMappedFiles {  
    9.     static final int LENGTH = 0x200000; // 2 Mb  
    10.     //static final int LENGTH = 100;  
    11.     static FileChannel fc;  
    12.   
    13.     public static void main(String[] args) throws Exception {  
    14.         //使用可随机访问文件创建可读写文件通道  
    15.         fc = new RandomAccessFile("test.txt", "rw").getChannel();  
    16.         //内存映射可读写文件,并映射至整个文件  
    17.         MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);  
    18.         for (int i = 0; i < LENGTH; i++) {//写满2M内容  
    19.             out.put((byte) 'x');  
    20.         }  
    21.         //锁定前1/3内容  
    22.         new LockAndModify(out, 0, 0 + LENGTH / 3);  
    23.         //从文件中间开始锁定1/4内容,注,要锁定的内容一定不能有与  
    24.         //已经锁定的内容,否则抛OverlappingFileLockException  
    25.         new LockAndModify(out, LENGTH / 2, LENGTH / 2 + LENGTH / 4);  
    26.     }  
    27.   
    28.     private static class LockAndModify extends Thread {  
    29.         private ByteBuffer buff;  
    30.         private int start, end;  
    31.   
    32.         LockAndModify(ByteBuffer mbb, int start, int end) {  
    33.             this.start = start;  
    34.             this.end = end;  
    35.   
    36.             //调整可最大读写位置  
    37.             mbb.limit(end);  
    38.             //调整读写起始位置  
    39.             mbb.position(start);  
    40.             //创建新的子缓冲区,但与原缓冲是共享同一片数据,  
    41.             //只是缓冲区位置、界限和标记值是相互独立的  
    42.             buff = mbb.slice();  
    43.             start();  
    44.         }  
    45.   
    46.         public void run() {  
    47.             try {  
    48.                 // 获取独占锁,如果要锁定的部分被其他应用程序锁定,则会阻塞,至到获取锁为止  
    49.                 FileLock fl = fc.lock(start, end, false);  
    50.                 System.out.println("Locked: " + start + " to " + end);  
    51.                 System.out.println(buff.position() + "  " + buff.limit());  
    52.   
    53.                 // 进行修改操作,前当前位置类  
    54.                 while (buff.position() < buff.limit() - 1) {  
    55.                     buff.put((byte) (buff.get() + 1));  
    56.                 }  
    57.                 //JVM退出,或者channel关闭的时候会自动释放这些锁,但是你也可以用FileLock  
    58.                 //的release( )方法,明确地释放锁,就像这里释放锁一样  
    59.                 fl.release();  
    60.                 System.out.println("Released: " + start + " to " + end);  
    61.             } catch (IOException e) {  
    62.                 throw new RuntimeException(e);  
    63.             }  
    64.         }  
    65.     }  
    66. }  
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    
    public class LockingMappedFiles {
    	static final int LENGTH = 0x200000; // 2 Mb
    	//static final int LENGTH = 100;
    	static FileChannel fc;
    
    	public static void main(String[] args) throws Exception {
    		//使用可随机访问文件创建可读写文件通道
    		fc = new RandomAccessFile("test.txt", "rw").getChannel();
    		//内存映射可读写文件,并映射至整个文件
    		MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
    		for (int i = 0; i < LENGTH; i++) {//写满2M内容
    			out.put((byte) 'x');
    		}
    		//锁定前1/3内容
    		new LockAndModify(out, 0, 0 + LENGTH / 3);
    		//从文件中间开始锁定1/4内容,注,要锁定的内容一定不能有与
    		//已经锁定的内容,否则抛OverlappingFileLockException
    		new LockAndModify(out, LENGTH / 2, LENGTH / 2 + LENGTH / 4);
    	}
    
    	private static class LockAndModify extends Thread {
    		private ByteBuffer buff;
    		private int start, end;
    
    		LockAndModify(ByteBuffer mbb, int start, int end) {
    			this.start = start;
    			this.end = end;
    
    			//调整可最大读写位置
    			mbb.limit(end);
    			//调整读写起始位置
    			mbb.position(start);
    			//创建新的子缓冲区,但与原缓冲是共享同一片数据,
    			//只是缓冲区位置、界限和标记值是相互独立的
    			buff = mbb.slice();
    			start();
    		}
    
    		public void run() {
    			try {
    				// 获取独占锁,如果要锁定的部分被其他应用程序锁定,则会阻塞,至到获取锁为止
    				FileLock fl = fc.lock(start, end, false);
    				System.out.println("Locked: " + start + " to " + end);
    				System.out.println(buff.position() + "  " + buff.limit());
    
    				// 进行修改操作,前当前位置类
    				while (buff.position() < buff.limit() - 1) {
    					buff.put((byte) (buff.get() + 1));
    				}
    				//JVM退出,或者channel关闭的时候会自动释放这些锁,但是你也可以用FileLock
    				//的release( )方法,明确地释放锁,就像这里释放锁一样
    				fl.release();
    				System.out.println("Released: " + start + " to " + end);
    			} catch (IOException e) {
    				throw new RuntimeException(e);
    			}
    		}
    	}
    }
  • 相关阅读:
    ACM TJU 1556
    HDU 1890 Robotie Sort
    Android学习笔记
    HDU 2795
    HDU 1542
    HDU 1698
    POJ 2185
    学习笔记
    HDU 3336
    HDU 3746
  • 原文地址:https://www.cnblogs.com/scott19820130/p/4609201.html
Copyright © 2011-2022 走看看