我正在尝试多线程导入作业,但遇到导致重复数据的问题。我需要将我的地图保留在循环之外,这样我的所有线程都可以更新并从中读取,但是如果没有它是最终的我就不能这样做,并且最终我无法更新地图。目前我需要将我的Map对象放在run方法中,但是当值最初不在数据库中并且每个线程创建一个新的时,问题就出现了。这会导致数据库中出现重复数据。有人知道如何做一些回电来更新我的地图吗?
ExecutorService executorService = Executors.newFixedThreadPool(10);
final Map<Integer, Object> map = new HashMap<>();
map.putAll(populate from database);
for (int i = 0; i < 10; i++) {
executorService.execute(new Runnable() {
public void run() {
while ((line = br.readLine()) != null) {
if(map.containsKey(123)) {
//read map object
session.update(object);
} else {
map.put(123,someObject);
session.save(object);
}
if(rowCount % 250 == 0)
tx.commit;
});
}
executorService.shutdown();
答案 0 :(得分:1)
您需要使用一些同步技术。
有问题的部分是当不同的线程试图将一些数据放入地图时。
示例:
线程1正在检查地图中是否存在具有键123的对象。在线程1添加新对象到映射之前,执行线程2。线程2还检查是否存在具有键123的对象。然后两个线程都将对象123添加到映射。这会导致重复......
您可以在此处详细了解同步
http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
答案 1 :(得分:1)
根据您的问题说明,您似乎想要一张数据一致的地图,并且您始终拥有最新的最新数据,而不会错过任何更新。
在这种情况下,您可以将地图映射为Collections.synchronizedMap()
。这将确保对地图的所有读写更新都进行同步,因此您可以保证使用地图中的最新数据查找密钥,并保证只对地图进行写入。
请参阅this SO讨论,了解与地图一起使用的并发技术之间的区别。
另外,还有一件事 - 将地图定义为最终不意味着你无法修改地图 - 你绝对可以在地图中添加和删除元素。但是,您无法做的是将变量更改为指向另一个地图。下面的简单代码片段说明了这一点:
private final Map<Integer, String> testMap = Collections.synchronizedMap(new HashMap<Integer,String>());
testMap.add(1,"Tom"); //OK
testMap.remove(1); //OK
testMap = new HashMap<Integer,String>(); //ERROR!! Cannot modify a variable with the final modifier
答案 2 :(得分:1)
我会建议以下解决方案
ConcurrentHashmap
update
和commit
save
和commit
。 伪码样本:
final Object lock = new Object();
...
executorService.execute(new Runnable() {
public void run() {
...
synchronized(lock){
if(concurrentMap.size() > 250){
saveInASeparateThread(concurrentMap.values().removeAll()));
}
}
}
}
答案 3 :(得分:1)
以下逻辑解决了我的问题。以下代码未经过测试。
ExecutorService executorService = Executors.newFixedThreadPool(10);
final Map<Integer, Object> map = new ConcurrentHashMap<>();
map.putAll(myObjectList);
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final thread = i;
Future future = executorService.submit(new Callable() {
public void call() {
List<MyObject> list;
CSVReader reader = new CSVReader(new InputStreamReader(csvFile.getStream()));
list = bean.parse(strategy, reader);
int listSize = list.size();
int rowCount = 0;
for(MyObject myObject : list) {
rowCount++;
Integer key = myObject.getId();
if(map.putIfAbsent(key, myObject) == null) {
session.save(object);
} else {
myObject = map.get(key);
//Do something
session.update(myObject);
}
if(rowCount % 250 == 0 || rowCount == listSize) {
tx.flush();
tx.clear();
}
};
tx.commit();
return "Thread " + thread + " completed.";
});
futures.add(future);
}
for(Future future : futures) {
System.out.println(future.get());
}
executorService.shutdown();