[转载] 文件锁(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,我们需能对此做相应处理。以下是简单的销实例:
- 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();
- }
- }
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();
}
}
锁定映射文件中的部分内容
文件映射通常用于很大的文件,因此我们可能需要对文件操作的部分进行加锁,以便其他进程可以修改文件中未被加锁的部分。
- 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);
- }
- }
- }
- }
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);
}
}
}
}
[转载] 文件锁(Filelock)与锁定映射文件部分内容的更多相关文章
- 用JUNCTION映射文件夹内容 解决多系统跑同一个虚拟机而共享文件夹路径不同的问题
事情由来: 某机器安装了俩系统,WIN7X64用来玩PC游戏,WIN2012R2用来工作,系统分别在两个不同的分区,但进入到系统后,两个系统的系统盘都是C盘.换句话说,在WIN7里,分区1是C盘,分区 ...
- Java NIO 内存映射文件
Java NIO 内存映射文件 @author ixenos 文件操作的四大方法 前提:内存的访问速度比磁盘高几个数量级,但是基本的IO操作是直接调用native方法获得驱动和磁盘交互的,IO速度限制 ...
- 【转】hibernate中的映射文件xxx.hbm.xml详解总结
一.Hibernate映射文件的作用: Hibernate映射文件是Hibernate与数据库进行持久化的桥梁 二,Hibernate映射文件主要内容: (1).映射内容的定义: Hibern ...
- Hibernate映射文件详解(News***.hbm.xml)二
转自 http://blog.csdn.net/a9529lty/article/details/6454924 一.hibernate映射文件的作用: Hibernate映射文件是Hibernate ...
- 框架学习系列 mybatis mapper映射文件之输出映射
1: mapper映射文件输出映射(输入类型) 2:resultType的使用 3:resultMap的使用 3:总结&下节预告 本文是<凯哥陪你学系列-框架学习之mybatis框架学习 ...
- hibernate中的映射文件xxx.hbm.xml详解总结
转自 http://blog.csdn.net/a9529lty/article/details/6454924 一.hibernate映射文件的作用: Hibernate映射文件是Hibernate ...
- [Nhibernate]SchemaExport工具的使用(一)——通过映射文件修改数据表
目录 写在前面 文档与系列文章 SchemaExport工具 SchemaUpdate工具 一个例子 总结 写在前面 上篇文章介绍了使用代码生成器的nhibernate模版来生成持久化类,映射文件等内 ...
- Hibernate第三篇【主配置文件、映射文件、复合主键映射】
前言 目前已经学了如何搭建Hibernate的开发环境,以及Hibernate对应的API了-在快速入门还没讲解的就是配置文件是怎么配置的.因此,本博文主要讲解主配置文件以及映射配置文件.. 主配置文 ...
- NET 4 中 内存映射文件
原文链接 : http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net- ...
随机推荐
- Python 基础系列一:初识python(二)基本数据类型
上节拾遗 1.编码转换过程,utf-8转换gbk 过程 经过解码(py27): x.decode('utf-8')-->unicode-->编码x.encode('gbk') ps:py3 ...
- 用C#实现字符串相似度算法(编辑距离算法 Levenshtein Distance)
在搞验证码识别的时候需要比较字符代码的相似度用到"编辑距离算法",关于原理和C#实现做个记录. 据百度百科介绍: 编辑距离,又称Levenshtein距离(也叫做Edit Dist ...
- 分页查询不知你是否真正的懂和PHP的正则的应用和一些性能优化
一.不废话太多 直接进入例子. 1 问题: 有一张收藏表,里面存储的是用户和图书ID.数据量为1亿.现在要求分页获取所有用户ID(不重复),写下你的sql语句. 表结构大致如下: ...
- 分布式锁的实现(redis)
1.单机锁 考虑在并发场景并且存在竞态的状况下,我们就要实现同步机制了,最简单的同步机制就是加锁. 加锁可以帮我们锁住资源,如内存中的变量,或者锁住临界区(线程中的一段代码),使得同一个时刻只有一个线 ...
- Scrapy架构及其组件之间的交互
最近在学Python,同时也在学如何使用python抓取数据,于是就被我发现了这个非常受欢迎的Python抓取框架Scrapy,下面一起学习下Scrapy的架构,便于更好的使用这个工具. 一.概述 下 ...
- ubuntu 14.04 vim YoucompleteMe 代码自动补全工具安装
安装步骤如下: sudo apt-get install vim ; sudo apt-get install vim-youcompleteme ; sudo apt-get install vim ...
- 数据结构与算法--从平衡二叉树(AVL)到红黑树
数据结构与算法--从平衡二叉树(AVL)到红黑树 上节学习了二叉查找树.算法的性能取决于树的形状,而树的形状取决于插入键的顺序.在最好的情况下,n个结点的树是完全平衡的,如下图"最好情况&q ...
- Vue.js2.0中的变化(持续更新中)
最近自己在学习Vue.js,在看一些课程的时候可能Vue更新太块了导致课程所讲知识和现在Vue的版本不符,从而报错,我会在以后的帖子持续更新Vue的变化与更新,大家也可以一起交流,共同监督学习! 1. ...
- Git相关操作一
1.将目录变为Git项目: 输入git init将当期目录变为Git项目 git init git项目可以被认为分为三个区域,Working Directory,Staging Area,Reposi ...
- Swift 之Protocol在cocoa中的使用范例搜集(一)
protocol Reusable: class { static var reuseIndentifier: String {get} static var nib: UINib? {get} } ...