java 多进程写一个文件_java高并发多线程及多进程同时写入文件研究
測(cè)試&思考:
環(huán)境:windows 七、linux centos 6.三、java8html
java多線程同時(shí)寫一個(gè)文件
java高并發(fā)環(huán)境下多線程同時(shí)寫入一個(gè)文件時(shí),
經(jīng)過 FileLock 加鎖,能夠控制對(duì)文件的并發(fā)操做。同一個(gè)JVM,能夠共享部份內(nèi)存java
第一種狀況是:一個(gè)線程A有對(duì)文件加鎖,另外一個(gè)線程B沒對(duì)文件加鎖
在windows7環(huán)境下:(持有鎖的能夠?qū)懳募晒?。
持有鎖的線程A會(huì)有對(duì)文件的操做權(quán)限,沒加鎖的線程B沒有對(duì)文件的操做權(quán)限,會(huì)報(bào)錯(cuò)退出,以下:linux
java.io.IOException: 另外一個(gè)程序已鎖定文件的一部分,進(jìn)程沒法訪問。
在linux centos 6.3環(huán)境下:(均可以寫文件成功,表現(xiàn)為數(shù)據(jù)交叉寫入)
互不影響,線程A和B都有對(duì)文件的操做權(quán)限web
第二種狀況兩個(gè)線程都有加鎖
在windows7環(huán)境和linux centos 6.3環(huán)境下表現(xiàn)同樣:(持有鎖的能夠?qū)懳募晒?
一個(gè)線程A競(jìng)爭(zhēng)到鎖,會(huì)有對(duì)文件的操做權(quán)限,另外一個(gè)線程B沒有競(jìng)爭(zhēng)到鎖,沒有對(duì)文件的操做權(quán)限,會(huì)報(bào)錯(cuò)退出,而不是發(fā)生阻塞。以下:shell
java.nio.channels.OverlappingFileLockException
在高并的這種生產(chǎn)狀況下,須要捕獲這個(gè)異常,并處理,以下:windows
while (true) {
try {
flout = fcout.tryLock();
break;
} catch (Exception e) {
//計(jì)數(shù)等其余操做...
sleep(1000);
}
}
多進(jìn)程同時(shí)寫一個(gè)文件
若是同為java進(jìn)程,則是不一樣的JVM。不能夠共享內(nèi)存centos
若是同為java進(jìn)程,一個(gè)進(jìn)程A有對(duì)文件加鎖,另外一個(gè)進(jìn)程B沒對(duì)文件加鎖
在windows7環(huán)境下:(持有鎖的能夠?qū)懳募晒?。
持有鎖的進(jìn)程 A會(huì)有對(duì)文件的操做權(quán)限,沒加鎖的進(jìn)程 B沒有對(duì)文件的操做權(quán)限,會(huì)報(bào)錯(cuò)退出,以下:服務(wù)器
java.io.IOException: 另外一個(gè)程序已鎖定文件的一部分,進(jìn)程沒法訪問。
在linux centos 6.3環(huán)境下:(均可以寫文件成功,表現(xiàn)為數(shù)據(jù)交叉寫入)
互不影響,進(jìn)程A和B都有對(duì)文件的操做權(quán)限多線程
若是同為java進(jìn)程,兩個(gè)進(jìn)程都加鎖
在windows7環(huán)境和linux centos 6.3環(huán)境下表現(xiàn)同樣:
誰(shuí)先得到鎖,誰(shuí)先得到對(duì)文件的操做權(quán)限,另外一個(gè)進(jìn)程則會(huì)等待第一個(gè)進(jìn)程處理完成,才會(huì)得到鎖,再對(duì)文件進(jìn)行處理。在這里是發(fā)生阻塞,而不是拋出異常(注意與多線程加鎖的區(qū)別)。
由此能夠證實(shí):針對(duì)對(duì)多進(jìn)程同時(shí)操做同一個(gè)文件,在這里應(yīng)該是底層JVM層面或者本地方法接口庫(kù)對(duì)這個(gè)文件進(jìn)行了加鎖。并發(fā)
一個(gè)為java進(jìn)程,另外一個(gè)為非Java進(jìn)程
此處操做全在服務(wù)器centos6.3上測(cè)試,非Java進(jìn)程為簡(jiǎn)單的 shell 進(jìn)程,例如:
for((i=1;i<10;i++));do echo 333 >> tmp.txt;sleep 1; done
java進(jìn)程無(wú)鎖的狀況
互不影響,java進(jìn)程和非java進(jìn)程都有對(duì)文件的操做權(quán)限
java進(jìn)程無(wú)鎖的狀況
互不影響,java進(jìn)程和非java進(jìn)程都有對(duì)文件的操做權(quán)限
總結(jié)
因而可知,在java高并發(fā)(不管是多線程仍是多進(jìn)程)同時(shí)操做文件時(shí)。
若是沒有文件順序的限制,能夠不加鎖,在這里有操做系統(tǒng)為咱們兜底(這里有風(fēng)險(xiǎn),是否是全部的操做系統(tǒng)都為咱們兜底呢)不會(huì)產(chǎn)生臟數(shù)據(jù);
若是有文件順序要求的限制,在這里不管是多線程仍是多進(jìn)程(前提是Java服務(wù)),均可以獲得很好的并發(fā)控制
若是能夠接受加鎖的開銷和復(fù)雜度,只要遇到并發(fā)操做文件時(shí)均可以加鎖。這樣能夠保證100%不會(huì)亂序,不用考慮是否操做系統(tǒng)會(huì)不會(huì)為咱們兜底了。
若是是使用FileLock try() 方法,同進(jìn)程內(nèi)的多線程訪問, lock會(huì)直接報(bào)OverlappingFileLockException, 而不是一直阻塞。 若是是多進(jìn)程, lock會(huì)一直阻塞,而不會(huì)包OverlappingFileLockException
這代表java提供的FileLock是面向整個(gè)虛擬機(jī)的,即進(jìn)程級(jí)別的。合理利用FileLock,加上多線程的異常處理控制。就能夠在多線程和多進(jìn)程場(chǎng)景下實(shí)現(xiàn)對(duì)文件的高并發(fā)訪問控制
FileLock 做用于java的進(jìn)程級(jí)別,不管獨(dú)占鎖、共享鎖都是針對(duì)不一樣的進(jìn)程,線程之間不適用。
測(cè)試代碼
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"));
//對(duì)該文件加鎖
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("有其余線程正在操做該文件,當(dāng)前線程休眠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 + "無(wú)鎖,寫文件共花了" + (System.currentTimeMillis() - t1) + "ms");
}
}
}
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的java 多进程写一个文件_java高并发多线程及多进程同时写入文件研究的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 对象 读写锁_读写锁的java
- 下一篇: java finally 抛出异常_ja