java多进程写⼀个⽂件_java⾼并发多线程及多进程同时写⼊⽂
件研究
测试&思考:
环境:windows 七、linux centos 6.三、java8html
java多线程同时写⼀个⽂件
java⾼并发环境下多线程同时写⼊⼀个⽂件时,
经过 FileLock 加锁,能够控制对⽂件的并发操做。同⼀个JVM,能够共享部份内存java
第⼀种状况是:⼀个线程A有对⽂件加锁,另外⼀个线程B没对⽂件加锁
在windows7环境下:(持有锁的能够写⽂件成功)。
持有锁的线程A会有对⽂件的操做权限,没加锁的线程B没有对⽂件的操做权限,会报错退出,以下:linux
java.io.IOException: 另外⼀个程序已锁定⽂件的⼀部分,进程没法访问。
在linux centos 6.3环境下:(均可以写⽂件成功,表现为数据交叉写⼊)
互不影响,线程A和B都有对⽂件的操做权限web
第⼆种状况两个线程都有加锁
在windows7环境和linux centos 6.3环境下表现同样:(持有锁的能够写⽂件成功)
⼀个线程A竞争到锁,会有对⽂件的操做权限,另外⼀个线程B没有竞争到锁,没有对⽂件的操做权限,会报错退出,⽽不是发⽣阻塞。以下:shell
java.nio.channels.OverlappingFileLockException
在⾼并的这种⽣产状况下,须要捕获这个异常,并处理,以下:windows
while (true) {
try {
flout = Lock();
break;
} catch (Exception e) {
//计数等其余操做...
sleep(1000);
}
}
多进程同时写⼀个⽂件
若是同为java进程,则是不⼀样的JVM。不能够共享内存centos
若是同为java进程,⼀个进程A有对⽂件加锁,另外⼀个进程B没对⽂件加锁
在windows7环境下:(持有锁的能够写⽂件成功)。
在linux centos 6.3环境下:(均可以写⽂件成功,表现为数据交叉写⼊)
互不影响,进程A和B都有对⽂件的操做权限多线程
若是同为java进程,两个进程都加锁
在windows7环境和linux centos 6.3环境下表现同样:
谁先得到锁,谁先得到对⽂件的操做权限,另外⼀个进程则会等待第⼀个进程处理完成,才会得到锁,再对⽂件进⾏处理。在这⾥是发⽣阻塞,⽽不是抛出异常(注意与多线程加锁的区别)。一个线程可以包含多个进程
由此能够证实:针对对多进程同时操做同⼀个⽂件,在这⾥应该是底层JVM层⾯或者本地⽅法接⼝库对这个⽂件进⾏了加锁。并发
⼀个为java进程,另外⼀个为⾮Java进程
此处操做全在服务器centos6.3上测试,⾮Java进程为简单的 shell 进程,例如:
for((i=1;i<10;i++));do echo 333 >> ;sleep 1; done
java进程⽆锁的状况
互不影响,java进程和⾮java进程都有对⽂件的操做权限
java进程⽆锁的状况
互不影响,java进程和⾮java进程都有对⽂件的操做权限
总结
因⽽可知,在java⾼并发(不管是多线程仍是多进程)同时操做⽂件时。
若是没有⽂件顺序的限制,能够不加锁,在这⾥有操做系统为咱们兜底(这⾥有风险,是否是全部的操做系统都为咱们兜底呢)不会产⽣脏数据;
若是有⽂件顺序要求的限制,在这⾥不管是多线程仍是多进程(前提是Java服务),均可以获得很好的并发控制
若是能够接受加锁的开销和复杂度,只要遇到并发操做⽂件时均可以加锁。这样能够保证100%不会乱序,不⽤考虑是否操做系统会不会为咱们兜底了。
若是是使⽤FileLock try() ⽅法,同进程内的多线程访问, lock会直接报OverlappingFileLockException, ⽽不是⼀直阻塞。 若是是多进程, lock会⼀直阻塞,⽽不会包OverlappingFileLockException
这代表java提供的FileLock是⾯向整个虚拟机的,即进程级别的。合理利⽤FileLock,加上多线程的异常处理控制。就能够在多线程和多进程场景下实现对⽂件的⾼并发访问控制
FileLock 做⽤于java的进程级别,不管独占锁、共享锁都是针对不⼀样的进程,线程之间不适⽤。
测试代码
package l.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 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("");
FileOutputStream output = null;
BufferedWriter br = null;
FileChannel fileChannel = null;
try {
output = new FileOutputStream(file, true);
br = new BufferedWriter(new OutputStreamWriter(output,"UTF-8")); //对该⽂件加锁
fileChannel = Channel();
FileLock fileLock = null;
fileLock = fileChannel.lock(0,Long.MAX_VALUE,false);
System.out.println(fileLock);
System.out.println(fileLock.isShared());
//⾮阻塞
/*while (true) {
try {
flout = Lock();
break;
} catch (Exception e) {
System.out.println("有其余线程正在操做该⽂件,当前线程休眠1000毫秒"); sleep(1000);
}
}*/
} 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("");
FileOutputStream output = null;
BufferedWriter br = null;
try {
output = new FileOutputStream(file, true);
br = new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
} 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"); }
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论