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 = fcout.tryLock();
break;
} catch (Exception e) {
//計數等其余操做...
sleep(1000);
}
}
多進程同時寫一個文件
若是同為java進程,則是不一樣的JVM。不能夠共享內存centos
若是同為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");
}
}
}
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的java 多进程写一个文件_java高并发多线程及多进程同时写入文件研究的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 对象 读写锁_读写锁的java
- 下一篇: java finally 抛出异常_ja