Java处理多人同时读写文件的文件锁处理

最近项目中有遇到并发同时访问一个文件读写的情况、但是同时读写就会出错、所以我研究了一下java文件锁这个机制下面直接贴代码

我通过的是线程来模拟多人同时读写的情况

写文件


[java] view plaincopyprint?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.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())+"秒");
}
}
读文件


[java] view plaincopyprint?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;

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();
}
}
}
调用

[java] view plaincopyprint?/**
*
*/
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();

}

}

/**
*
*/
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时 为共享锁


Java处理多人同时读写文件的文件锁处理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值