java多进程文件读写_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系统环境下关于多进程并发写同一个文件的讨论

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值