ファイルシステムに複数の項目を書き込み、あるスレッドが別のスレッドのデータを上書きしたり、別の項目のデータとインターリーブしたりすることを完全に期待しています。Javaの同時ファイル書き込み - 失敗する必要があります
ただし、次のコードは予期せず実行されます。
あるスレッドのデータが別のスレッドのデータを上書きしないのはなぜですか?すべてのスレッドは1人のライターを共有します。コードがJVM実装の詳細のために渡されるか、個々の項目を混ぜ合わせないことが本当に期待できるか?
私は、複数のスレッドが同じファイルに書き込むといういくつかのクエストを見たことがありますが、これはパフォーマンスの最適化に関するものでした。インポートスタイルは、投稿時の簡潔さのためだけのものです。
package com.test;
import static org.junit.Assert.assertEquals;
import java.io.*;
import java.nio.charset.*;
import java.nio.file.*;
import java.util.*;
import org.springframework.boot.CommandLineRunner;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DiskWriterApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
new DiskWriterApplication().run(args);
}
@Override
public void run(String... args) throws Exception {
Path path = Paths.get(System.getProperty("user.home")+"/java-file.txt");
if (!Files.exists(path)) {
Files.createFile(path);
} else {
Files.delete(path);
Files.createFile(path);
}
BufferedWriter writer = Files.newBufferedWriter(path, Charset.forName("UTF-8"), StandardOpenOption.APPEND);
Thread[] threads = new Thread[4];
for (int i=0; i< 4; i++) {
threads[i] = new Thread(new DataWriter(writer, createDataItems(i)));
}
Arrays.asList(threads).forEach(Thread::start);
Arrays.asList(threads).forEach(t-> {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
writer.close();
//Verify Lines were written correctly
ObjectMapper mapper = new ObjectMapper();
MappingIterator<Data> valueIterator = mapper.readerFor(Data.class).readValues(Files.newInputStream(path));
Set<String> uniqueItems = new HashSet<>();
int[] groupItemCount = new int[4];
while (valueIterator.hasNext())
{
Data item = valueIterator.next();
assertEquals("First Item and second Item should be equal", item.firstValue, item.secondValue);
assertEquals(10, item.innerObject.size());
assertEquals(20, item.listValues.size());
for (int i = 0 ; i< 10; i++) {
assertEquals(item.firstValue, item.innerObject.get("innerProp"+i));
}
for (int i = 0 ; i< 20; i++) {
assertEquals(item.firstValue, item.listValues.get(i));
}
uniqueItems.add(item.firstValue);
groupItemCount[item.group]++;
}
System.out.println("Got " + uniqueItems.size() + " uniqueItems");
assertEquals("Should be 4000 uniqueItems", 4000, uniqueItems.size());
assertEquals("Should be 1000 items in group[0]", 1000, groupItemCount[0]);
assertEquals("Should be 1000 items in group[1]", 1000, groupItemCount[1]);
assertEquals("Should be 1000 items in group[2]", 1000, groupItemCount[2]);
assertEquals("Should be 1000 items in group[3]", 1000, groupItemCount[3]);
}
private List<Data> createDataItems(int groupNumber) {
List<Data> items = new ArrayList<>();
for (int i =0; i<1000; i++) {
Data item = new Data();
item.group = groupNumber;
item.itemNumber = i;
item.firstValue = "{group" + groupNumber + "item" + i + "}";
item.secondValue = "{group" + groupNumber + "item" + i + "}";
for (int j =0; j< 10; j ++) {
item.addInnerProperty("innerProp"+j , "{group" + groupNumber + "item" + i + "}");
}
for (int j=0; j<20; j++) {
item.addListValue("{group" + groupNumber + "item" + i + "}");
}
items.add(item);
}
return items;
}
private class DataWriter implements Runnable {
private ArrayList<String> data;
private PrintWriter writer;
public DataWriter(BufferedWriter writer, List<Data> items) {
this.writer = new PrintWriter(writer);
this.data = new ArrayList<String>();
ObjectMapper mapper = new ObjectMapper();
for (Data i : items) {
try {
String stringValue = mapper.writeValueAsString(i);
data.add(stringValue);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void run() {
System.out.println("Starting batch");
data.forEach(t -> {
writer.println(t);
writer.flush();
});
System.out.println("finishing batch");
}
}
public static class Data {
public int itemNumber;
public int group;
@JsonProperty
private String firstValue;
@JsonProperty
private String secondValue;
@JsonProperty
private Map<String, String> innerObject = new HashMap<>();
@JsonProperty
private List<String> listValues = new ArrayList<>();
public void addInnerProperty(String key, String value){
this.innerObject.put(key, value);
}
public void addListValue(String value) {
this.listValues.add(value);
}
}
}
同期とスレッドセーフですか? – EJP
私はそれが失敗することを期待しました。申し訳ありませんがおそらく明らかではありませんでした。 – Wes
、ユーザーごとに3585566おそらくhttp://stackoverflow.com/questions/30080560/is-writting-on-file-using-bufferwriter-initialized-by-filewriter-thread-safe-またはその質問に答えます。 – Wes