我正在使用Java的并发执行器一次读取多个文件,并将信息写入哈希图。这些文件用于日常日志,如下所示:
+-----------+-------+-----------+-------+
| Member ID | Time | Weight | Fat % |
+-----------+-------+-----------+-------+
| 1123141 | 1:03 | 162 | 21.2 |
| 5321430 | 1:10 | 131 | 25.3 |
| ... | ... | ... | ... |
+-----------+-------+-----------+-------+
哈希表将成员名称作为键,对于值,我创建了一个“MemberProperties”类,该类具有时间和其他属性的列表。我试图使用多个线程一次读取多个天,将数据写入哈希图,然后在每个成员的基础上进行数据分析。这是代码的样子
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.ArrayList;
import java.util.Date;
import java.io.IOException;
class MemberProps {
ArrayList<Date> time;
ArrayList<Integer> weight;
ArrayList<Float> fat;
public MemberProps() {
this.time = new ArrayList<>();
this.weight = new ArrayList<>();
this.fat = new ArrayList<>();
}
}
public class MemberFileReader {
public ConcurrentHashMap<Integer, MemberProps> MemberHash;
public ExecutorService executor = Executors.newFixedThreadPool(2);
public void readFiles() {
//Get this week's files
File folder = new File("C:\\User\\Temp");
File[] files = folder.listFiles();
for (File fl : files) {
executor.execute(new FileReader(fl.toString()));
}
executor.shutdown();
}
private final class FileReader implements Runnable {
private String filepath;
public FileReader(String filepath) {
this.filepath = filepath;
}
@Override
public synchronized void run() {
try {
String line = null;
BufferedReader in = new BufferedReader(new FileReader(filepath));
while ((line = in.readLine()) != null) {
MemberProps member = new MemberProps();
String[] split_line = line.split("\\t");
int member_id = Integer.parseInt(split_line[0]);
member.time.add(Date.parse(split_line[1]));
member.weight.add(Integer.parseInt(split_line[2]));
member.fat.add(Float.parseFloat(split_line[3]));
// If not absent, will return member's values
member = MemberHash.putIfAbsent(member_id, member);
if (member != null){
member.time.add(Date.parse(split_line[1]));
member.weight.add(Integer.parseInt(split_line[2]));
member.fat.add(Float.parseFloat(split_line[3]));
MemberHash.put(member_id, member);
}
}
} catch (IOException E){
// caught exception
}
}
}
}
我的问题是,由于某种原因,列表中缺少值。例如,对于具有10个日志的成员,我可能有10次但只有9个权重/脂肪,或者类似的9次但有10个权重,依此类推。从调试看来,当不同的线程尝试对
get
相同时,可能会出现此问题成员和put
同时使用,但我不确定。有任何想法吗?为了解决这个问题,我正在考虑为每个线程使用不同的哈希映射,然后再加入映射,但如果有更简单的解决方案,请加入idk。 最佳答案
ArrayList.add不是线程安全的。您应该同步添加到MemberProps中的那些列表,例如
class MemberProps {
private ArrayList<Date> time;
private ArrayList<Integer> weight;
private ArrayList<Float> fat;
public MemberProps() {
this.time = new ArrayList<>();
this.weight = new ArrayList<>();
this.fat = new ArrayList<>();
}
public synchronized add(Date d, Integer w, Float f) {
this.time.add(d);
this.weight.add(d);
this.fat.add(f);
}
}
然后使用如下所示的同步方法:
if (member != null)) {
Date d = Date.parse(split_line[1]);
Integer w = Integer.parseInt(split_line[2]);
Float f = Float.parseFloat(split_line[3]);
member.add(d, w, f);
}
请注意,由于该成员已经存在,因此您不应再次将其放入地图中,而只需将其添加到现有实例中即可。