线程写:
package nio.lock;
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;
public class Thread_writeFile extends Thread {
@Override
public void run() {
Calendar calstart = Calendar.getInstance();
File file = new File("D:\\1701.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) {
// TODO Auto-generated catch block
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒!");
try {
sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
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) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Calendar calend=Calendar.getInstance();
System.out.println("写文件共花了:"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"毫秒");
}
}
线程读:
package nio.lock;
import java.io.File;
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;
public class Thread_readFile extends Thread {
@Override
public void run() {
Calendar calstart = Calendar.getInstance();
try {
// sleep(25000);
sleep(5000); //同时读写
File file = new File("D:\\1701.txt");
// 给该文件加锁
RandomAccessFile fis = new RandomAccessFile(file, "rw");
FileChannel fcin = fis.getChannel();
FileLock flin = null;
while (true) {
try {
flin = fcin.tryLock();
break;
} catch (IOException 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 (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试:
package nio.lock;
public class Test {
public static void main(String[] args) {
Thread_writeFile wr=new Thread_writeFile();
Thread_readFile rf=new Thread_readFile();
wr.start();
rf.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时,为共享锁