http://blog.csdn.net/gxy3509394/article/details/7435993
最近项目中有遇到并发同时访问一个文件读写的情况、但是同时读写就会出错、所以我研究了一下java文件锁这个机制下面直接贴代码
我通过的是线程来模拟多人同时读写的情况
写文件
- package com.dnion.test;
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.channels.FileChannel;
- import java.nio.channels.FileLock;
- import java.util.Calendar;
- /**
- * @author chb
- */
- public class Thread_writeFile extends Thread{
- public void run(){
- Calendar calstart=Calendar.getInstance();
- File file=new File("D:/test.txt");
- try {
- if(!file.exists())
- file.createNewFile();
- //对该文件加锁
- RandomAccessFile out = new RandomAccessFile(file, "rw");
- FileChannel fcout=out.getChannel();
- FileLock flout=null;
- while(true){
- try {
- flout = fcout.tryLock();
- break;
- } catch (Exception e) {
- System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
- sleep(1000);
- }
- }
- for(int i=1;i<=1000;i++){
- sleep(10);
- StringBuffer sb=new StringBuffer();
- sb.append("这是第"+i+"行,应该没啥错哈 ");
- out.write(sb.toString().getBytes("utf-8"));
- }
- flout.release();
- fcout.close();
- out.close();
- out=null;
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- Calendar calend=Calendar.getInstance();
- System.out.println("写文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
- }
- }
读文件
- package com.dnion.test;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.channels.FileChannel;
- import java.nio.channels.FileLock;
- import java.util.Calendar;
- /**
- * @author chb
- */
- public class Thread_readFile extends Thread{
- public void run(){
- try {
- Calendar calstart=Calendar.getInstance();
- sleep(5000);
- File file=new File("D:/test.txt");
- //给该文件加锁
- RandomAccessFile fis = new RandomAccessFile(file, "rw");
- FileChannel fcin=fis.getChannel();
- FileLock flin=null;
- while(true){
- try {
- flin = fcin.tryLock();
- break;
- } catch (Exception e) {
- System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
- sleep(1000);
- }
- }
- byte[] buf = new byte[1024];
- StringBuffer sb=new StringBuffer();
- while((fis.read(buf))!=-1){
- sb.append(new String(buf,"utf-8"));
- buf = new byte[1024];
- }
- System.out.println(sb.toString());
- flin.release();
- fcin.close();
- fis.close();
- fis=null;
- Calendar calend=Calendar.getInstance();
- System.out.println("读文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
- }catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
调用
- /**
- *
- */
- package com.dnion.test;
- /**
- * @author Administrator
- *
- */
- public class Test {
- /**
- * @param args
- */
- public static void main(String[] args) {
- Thread_writeFile thf3=new Thread_writeFile();
- Thread_readFile thf4=new Thread_readFile();
- thf3.start();
- thf4.start();
- }
- }
这里我们要讲解一下文件锁
我们通过RandomAccessFile这个随机读取流来操作文件速度上面会有一点慢、但不是极其大的文件一般可以忽略。
我们通过FileChannel对象来获得锁
Trylock 与lock方法
tryLock()是非阻塞式的,它设法获取锁,但如果不能获得,例如因为其他一些进程已经持有相同的锁,而且不共享时,它将直接从方法调用返回。
lock()是阻塞式的,它要阻塞进程直到锁可以获得,或调用lock()的线程中断,或调用lock()的通道关闭。
对独占锁和共享锁的支持必须由底层的操作系统提供。锁的类型可以通过FileLock.isShared()进行查询。另外,我们不能获取缓冲器上的锁,只能是通道上的。
OverlappingFileLockException 与锁的作用域
在某个文件加锁锁只会作用在此文件上对其他文件无效
单个 Java 虚拟机在某个特定文件上所保持的锁定是不重叠的,即同一个jvm中不同线程去拿同一文件的锁时,先拿到的获得锁,后获取的无法获得锁,tryLock()方法不会抛出异常,但获得锁值为null。
不同jvm或者不同操作系统获取同一文件锁时,先拿到的获得锁,后获取的抛出文件重叠锁异常【OverlappingFileLockException】。以上是windows才会出现如此现象,如果是linux 会抛出异常:【java.io.IOException:Permission denied】
共享锁与独占锁区别
独占锁:也称排它锁,如果一个线程获得一个文件的独占锁,那么其它线程就不能再获得同一文件的独占锁或共享锁,直到独占锁被释放。
共享锁:如果一个线程获得一个文件的共享锁,那么其它线程可以获得同一文件的共享锁或同一文件部分内容的共享锁,但不能获取排它锁
当a.txt文件被加独占锁时 其他线程不可读也不可写
当a.txt文件被加共享锁时 其他线程可读也不可写
如何获得共享锁
fc.tryLock(position,size,isShare);第三个参数为true时 为共享锁