[转载] 文件锁(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. public class FileLocking {
  4. public static void main(String[] args) throws Exception {
  5. FileOutputStream fos = new FileOutputStream("file.txt");
  6. //获取文件锁 FileLock 对象
  7. FileLock fl = fos.getChannel().tryLock();
  8. //tryLock是尝试获取锁,有可能为空,所以要判断
  9. if (fl != null) {
  10. System.out.println("Locked File");
  11. Thread.sleep(100);
  12. fl.release();//释放锁
  13. System.out.println("Released Lock");
  14. }
  15. fos.close();
  16. }
  17. }
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. public class LockingMappedFiles {
  8. static final int LENGTH = 0x200000; // 2 Mb
  9. //static final int LENGTH = 100;
  10. static FileChannel fc;
  11. public static void main(String[] args) throws Exception {
  12. //使用可随机访问文件创建可读写文件通道
  13. fc = new RandomAccessFile("test.txt", "rw").getChannel();
  14. //内存映射可读写文件,并映射至整个文件
  15. MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
  16. for (int i = 0; i < LENGTH; i++) {//写满2M内容
  17. out.put((byte) ‘x‘);
  18. }
  19. //锁定前1/3内容
  20. new LockAndModify(out, 0, 0 + LENGTH / 3);
  21. //从文件中间开始锁定1/4内容,注,要锁定的内容一定不能有与
  22. //已经锁定的内容,否则抛OverlappingFileLockException
  23. new LockAndModify(out, LENGTH / 2, LENGTH / 2 + LENGTH / 4);
  24. }
  25. private static class LockAndModify extends Thread {
  26. private ByteBuffer buff;
  27. private int start, end;
  28. LockAndModify(ByteBuffer mbb, int start, int end) {
  29. this.start = start;
  30. this.end = end;
  31. //调整可最大读写位置
  32. mbb.limit(end);
  33. //调整读写起始位置
  34. mbb.position(start);
  35. //创建新的子缓冲区,但与原缓冲是共享同一片数据,
  36. //只是缓冲区位置、界限和标记值是相互独立的
  37. buff = mbb.slice();
  38. start();
  39. }
  40. public void run() {
  41. try {
  42. // 获取独占锁,如果要锁定的部分被其他应用程序锁定,则会阻塞,至到获取锁为止
  43. FileLock fl = fc.lock(start, end, false);
  44. System.out.println("Locked: " + start + " to " + end);
  45. System.out.println(buff.position() + "  " + buff.limit());
  46. // 进行修改操作,前当前位置类
  47. while (buff.position() < buff.limit() - 1) {
  48. buff.put((byte) (buff.get() + 1));
  49. }
  50. //JVM退出,或者channel关闭的时候会自动释放这些锁,但是你也可以用FileLock
  51. //的release( )方法,明确地释放锁,就像这里释放锁一样
  52. fl.release();
  53. System.out.println("Released: " + start + " to " + end);
  54. } catch (IOException e) {
  55. throw new RuntimeException(e);
  56. }
  57. }
  58. }
  59. }
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);
			}
		}
	}
}
时间: 2024-08-07 19:52:43

[转载] 文件锁(Filelock)与锁定映射文件部分内容的相关文章

用JUNCTION映射文件夹内容 解决多系统跑同一个虚拟机而共享文件夹路径不同的问题

事情由来: 某机器安装了俩系统,WIN7X64用来玩PC游戏,WIN2012R2用来工作,系统分别在两个不同的分区,但进入到系统后,两个系统的系统盘都是C盘.换句话说,在WIN7里,分区1是C盘,分区2是D盘,但是到了WIN2012R2里,分区2是C盘,分区1是D盘.这么导致的后果是,虚拟机里映射的盘符,在另外一个系统就不可用了.比如我在WIN7里,把C:\TEST映射到了“NET虚拟机”的共享文件夹,但是到了WIN2012R2里,C:\TEST的实际路径是D:\TEST,这时候在“NET虚拟机

【转载】vim 比较两个文件的内容

1. 使用vim的比较模式打开两个文件: vim -d file1 file2 或 vimdiff file1 file2 2. 如果已经打开了文件file1,再打开另一个文件file2进行比较: :vert diffsplit file2 如果没有用vert命令,diffsplit则会分上下两个窗口. 3. 如果已经用split方式打开了两个文件file1,file2,又想比较两文件的不同. 分别在两个窗口里面输入命令: :diffthis 4. 如果更改了某个窗口的内容,vim又没有自动更新

hibernate中的映射文件xxx.hbm.xml详解总结

转自 http://blog.csdn.net/a9529lty/article/details/6454924 一.hibernate映射文件的作用: Hibernate映射文件是Hibernate与数据库进行持久化的桥梁   二,Hibernate映射文件主要内容:     (1).映射内容的定义: Hibernate映射文件由<hibernate-mapping package="JavaBean所在包的全路径">节点定义映射内容并指定所对应的JavaBean的位置(

NET 4 中 内存映射文件

原文链接 : http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx 预备知识 : 本文需要你对 OS 内存管理有一定了解. 我想探索下即将到来的 .NET 4 中一些与众不同的新特性,而不是已被大众所熟知的动态类型.协变与逆变等特性.出于对性能增强的喜爱,接下来俺将发表几篇新特性的博文. 内存映射文件对于托管世界的开发人员来说,似乎就像是火星人一样陌生

[Nhibernate]SchemaExport工具的使用(一)——通过映射文件修改数据表

目录 写在前面 文档与系列文章 SchemaExport工具 SchemaUpdate工具 一个例子 总结 写在前面 上篇文章介绍了使用代码生成器的nhibernate模版来生成持久化类,映射文件等内容.本篇文章将继续介绍工具SchemaExport和SchemaUpdate.说实话,这东西我也是第一次使用,也只能边摸索,边学习了. 一般的开发模式是先将数据库架构设计好,然后再编写持久化类和映射文件,也就是数据库驱动的模式.然而也可以先编写持久化类和映射文件,然后通过SchemaExport工具

8、Hibernate框架(ORM详解、主文件配置、映射文件配置)

开发回顾: SSH框架: Struts框架, 基于mvc模式的应用层框架技术! Hibernate, 基于持久层的框架(数据访问层使用)! Spring, 创建对象处理对象的依赖关系以及框架整合! Dao代码,如何编写? - 操作XML数据 - 使用Jdbc技术 原始的jdbc操作, Connection/Statement/ResultSet 自定义一个持久层框架, 封装了dao的通用方法 DbUtils组件, 轻量级的dao的组件: Hibernate技术 [hibernate最终执行的也是

NHibernate之映射文件配置说明(转载1)

源博客:http://www.cnblogs.com/kissdodog/archive/2013/02/21/2919886.html 1. hibernate-mapping 这个元素包括以下可选的属性.schema属性,指明了这个映射所引用的表所在的schema名称.假若指定了这个属性, 表名会加上所指定的schema的名字扩展为全限定名.假若没有指定,表名就不会使用全限定名.default-cascade 指定了未明确注明cascade属性的.Net属性和集合类.Net会采取什么样的默认

内存映射文件原理探索(转载)

转载:http://blog.chinaunix.net/uid-20761674-id-3072683.html 一直都对内存映射文件这个概念很模糊,不知道它和虚拟内存有什么区别,而且映射这个词也很让人迷茫,今天终于搞清楚了...下面,我先解释一下我对映射这个词的理解,再区分一下几个容易混淆的概念,之后,什么是内存映射就很明朗了. 原理 首先,"映射"这个词,就和数学课上说的"一一映射"是一个意思,就是建立一种一一对应关系,在这里主要是只 硬盘上文件 的位置与进程

NHibernate之映射文件配置说明(转载3)

十二.组件(component), 动态组件(dynamic-component) <component>元素把子对象的一些元素与父类对应的表的一些字段映射起来. 然后组件可以定义它们自己的属性.组件或者集合. <component name="PropertyName" (1) class="ClassName" (2) insert="true|false" (3) upate="true|false"