失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > java高并发多线程及多进程同时写入文件研究

java高并发多线程及多进程同时写入文件研究

时间:2022-09-06 13:00:37

相关推荐

java高并发多线程及多进程同时写入文件研究

文章目录

测试&思考:java多线程同时写一个文件第一种情况是:一个线程A有对文件加锁,另一个线程B没对文件加锁在windows7环境下:(持有锁的可以写文件成功)。在linux centos 6.3环境下:(都可以写文件成功,表现为数据交叉写入)第二种情况两个线程都有加锁在windows7环境和linux centos 6.3环境下表现一样:(持有锁的可以写文件成功)多进程同时写一个文件如果同为java进程,一个进程A有对文件加锁,另一个进程B没对文件加锁在windows7环境下:(持有锁的可以写文件成功)。在linux centos 6.3环境下:(都可以写文件成功,表现为数据交叉写入)如果同为java进程,两个进程都加锁在windows7环境和linux centos 6.3环境下表现一样:一个为java进程,另一个为非Java进程java进程无锁的情况java进程无锁的情况总结测试代码

测试&思考:

环境:windows 7、linux centos 6.3、java8

java多线程同时写一个文件

java高并发环境下多线程同时写入一个文件时,

通过 FileLock 加锁,可以控制对文件的并发操作。同一个JVM,可以共享部分内存

第一种情况是:一个线程A有对文件加锁,另一个线程B没对文件加锁

在windows7环境下:(持有锁的可以写文件成功)。

持有锁的线程A会有对文件的操作权限,没加锁的线程B没有对文件的操作权限,会报错退出,如下:

java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。

在linux centos 6.3环境下:(都可以写文件成功,表现为数据交叉写入)

互不影响,线程A和B都有对文件的操作权限

第二种情况两个线程都有加锁

在windows7环境和linux centos 6.3环境下表现一样:(持有锁的可以写文件成功)

一个线程A竞争到锁,会有对文件的操作权限,另一个线程B没有竞争到锁,没有对文件的操作权限,会报错退出,而不是发生阻塞。如下:

java.nio.channels.OverlappingFileLockException

在高并的这种生产情况下,需要捕获这个异常,并处理,如下:

while (true) {try {flout = fcout.tryLock();break;} catch (Exception e) {//计数等其他操作...sleep(1000);}}

多进程同时写一个文件

如果同为java进程,则是不同的JVM。不可以共享内存

如果同为java进程,一个进程A有对文件加锁,另一个进程B没对文件加锁

在windows7环境下:(持有锁的可以写文件成功)。

持有锁的进程A会有对文件的操作权限,没加锁的进程B没有对文件的操作权限,会报错退出,如下:

java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。

在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 >> tmp.txt;sleep 1; done

java进程无锁的情况

互不影响,java进程和非java进程都有对文件的操作权限

java进程无锁的情况

互不影响,java进程和非java进程都有对文件的操作权限

总结

由此可见,在java高并发(无论是多线程还是多进程)同时操作文件时。

如果没有文件顺序的限制,可以不加锁,在这里有操作系统为我们兜底(这里有风险,是不是所有的操作系统都为我们兜底呢)不会产生脏数据;如果有文件顺序要求的限制,在这里无论是多线程还是多进程(前提是Java服务),都可以得到很好的并发控制如果可以接受加锁的开销和复杂度,只要遇到并发操作文件时都可以加锁。这样可以保证100%不会乱序,不用考虑是否操作系统会不会为我们兜底了。如果是使用FileLock try() 方法,同进程内的多线程访问, lock会直接报OverlappingFileLockException, 而不是一直阻塞。 如果是多进程, lock会一直阻塞,而不会包OverlappingFileLockException这表明java提供的FileLock是面向整个虚拟机的,即进程级别的。合理利用FileLock,加上多线程的异常处理控制。就可以在多线程和多进程场景下实现对文件的高并发访问控制FileLock 作用于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系统环境下关于多进程并发写同一个文件的讨论

如果觉得《java高并发多线程及多进程同时写入文件研究》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。