环境:windows 7、linux centos 6.3、java8
java高并发环境下多线程同时写入一个文件时,
通过 FileLock 加锁,可以控制对文件的并发操作。同一个JVM,可以共享部分内存
持有锁的线程A会有对文件的操作权限,没加锁的线程B没有对文件的操作权限,会报错退出,如下:
java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。
互不影响,线程A和B都有对文件的操作权限
一个线程A竞争到锁,会有对文件的操作权限,另一个线程B没有竞争到锁,没有对文件的操作权限,会报错退出,而不是发生阻塞。如下:
java.nio.channels.OverlappingFileLockException
在高并的这种生产情况下,需要捕获这个异常,并处理,如下:
while (true) {
try {
flout = fcout.tryLock();
break;
} catch (Exception e) {
//计数等其他操作...
sleep(1000);
}
}
如果同为java进程,则是不同的JVM。不可以共享内存
持有锁的进程 A会有对文件的操作权限,没加锁的进程 B没有对文件的操作权限,会报错退出,如下:
java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。
互不影响,进程A和B都有对文件的操作权限
谁先获得锁,谁先获得对文件的操作权限,另一个进程则会等待第一个进程处理完成,才会获得锁,再对文件进行处理。在这里是发生阻塞,而不是抛出异常(注意与多线程加锁的区别)。
由此可以证明:针对对多进程同时操作同一个文件,在这里应该是底层JVM层面或者本地方法接口库对这个文件进行了加锁。
此处操作全在服务器centos6.3上测试,非Java进程为简单的 shell 进程,例如:
for((i=1;i<10;i++));do echo 333 >> tmp.txt;sleep 1; done
互不影响,java进程和非java进程都有对文件的操作权限
互不影响,java进程和非java进程都有对文件的操作权限
由此可见,在java高并发(无论是多线程还是多进程)同时操作文件时。
package com.dxm.etl.test;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class TestFileLock {
public static void main(String args[]) throws Exception {
System.out.println(Thread.currentThread().getName());
// new ThreadWriteFileWithoutLock("111").start();
// Thread.sleep(1000);
new ThreadWriteFileWithLock("222").start();
}
private static class ThreadWriteFileWithLock extends Thread {
private String threadName;
public ThreadWriteFileWithLock(String threadName) {
this.threadName = threadName;
}
public void run() {
long t1 = System.currentTimeMillis();
File file = new File("tmp.txt");
FileOutputStream output = null;
BufferedWriter br = null;
FileChannel fileChannel = null;
try {
output = new FileOutputStream(file, true);
br = new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
//对该文件加锁
fileChannel = output.getChannel();
FileLock fileLock = null;
fileLock = fileChannel.lock(0,Long.MAX_VALUE,false);
System.out.println(fileLock);
System.out.println(fileLock.isShared());
//非阻塞
/*while (true) {
try {
flout = fcout.tryLock();
break;
} catch (Exception e) {
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
sleep(1000);
}
}*/
for (int i = 1; i <= 10; i++) {
sleep(1000);
br.write(threadName+"\n");
br.flush();
}
fileLock.release();
} catch (Exception e) {
e.printStackTrace();
System.out.println(threadName +" err");
} finally {
try {
br.close();
fileChannel.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(threadName + "有锁,写文件共花了" + (System.currentTimeMillis() - t1) + "ms");
}
}
public static class ThreadWriteFileWithoutLock extends Thread {
private String threadName;
public ThreadWriteFileWithoutLock(String threadName) {
this.threadName = threadName;
}
public void run() {
long t1 = System.currentTimeMillis();
File file = new File("tmp.txt");
FileOutputStream output = null;
BufferedWriter br = null;
try {
output = new FileOutputStream(file, true);
br = new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
for (int i = 1; i <= 10; i++) {
sleep(1000);
br.write(threadName+"\n");
br.flush();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(threadName +" err");
} finally {
try {
br.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(threadName + "无锁,写文件共花了" + (System.currentTimeMillis() - t1) + "ms");
}
}
}
参考:
JAVA 文件锁 FileLock
Java处理多人同时读写文件的文件锁处理
Java 进程间文件锁FileLock详解
Linux系统环境下关于多进程并发写同一个文件的讨论