以事务方式更改集合中的记录



我有这个代码:

import java.util.*;

class MyClass {
public Boolean field;
}

public class Main {
Map<String, MyClass> map = new HashMap<>();
private void fillCollection() {
MyClass record1 = new MyClass();
MyClass record2 = new MyClass();
MyClass record3 = new MyClass();
record1.field = false;
record2.field = false;
record3.field = false;
map.put("record1", record1);
map.put("record2", record2);
map.put("record3", record3);
}
private void changeObject(MyClass record) throws Exception {
if (new Random().nextInt(2) == 0) {
throw new Exception("Exception during Object change");
}
record.field = true;
}
private void changeCollection(List<String> recordKeys) {
for (String key : recordKeys) {
try {
changeObject(map.get(key));
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void printCollection() {
for (String key : map.keySet()) {
System.out.println(key + " " + map.get(key).field);
}
}
public static void main(String[] args) throws Exception {
Main application = new Main();
new Thread(new Runnable() {
@Override
public void run() {
application.fillCollection();
}
}).start();
Thread.sleep(100);
new Thread(new Runnable() {
@Override
public void run() {
List<String> recordKeys = new ArrayList<>();
recordKeys.add("record1");
recordKeys.add("record2");
application.changeCollection(recordKeys);
}
}).start();
Thread.sleep(100);
new Thread(new Runnable() {
@Override
public void run() {
application.printCollection();
}
}).start();
}
}

刨光:

  • 有对象映射(键是字符串(。

  • 在一个线程中,此映射填充了对象。

  • 在其他线程中,应该更改某些(不是全部(对象。在 Object 的更改过程中,可能会抛出一些异常(在上述情况下,它在方法 "changeObject" 中模拟(。在异常的情况下,不应将对象添加到地图中。

事情是这样的:在 Map 中添加所有对象应该是事务性的。也许我在这里没有使用"严谨"这个词,所以我解释说:最后要么所有记录都应该改变,要么什么都不应该改变。

所以问题是:它能实现吗?"changeCollection"方法应该是什么样子的?

目前我使用以下解决方案:我创建临时地图,用主地图中的记录克隆填充它,尝试更改此临时地图中的克隆记录,如果没有异常,我使主地图变量指向临时地图对象。我不喜欢这个解决方案,如果存在,我更喜欢没有克隆的解决方案。

另一件事:我不想给你任何外部库。

是的,这是可以实现的。请看下面的片段。

public class MapWrapper {
// this needs to be volatile
private volatile Map<String, MyClass> map;
// this needs to be synchronized 
public synchronized fillMap() {
// you have single access to the map, fill it as needed
}
// this needs to be synchronized 
public synchronized editMap() {
// you have single access to the map
Map<String, MyClass> clone = deepCloneMap(map); 
try {
// modify the clone map
// as the last instruction in the try block, reassign references 
map = clone; 
} catch (Exception e) {
// deal with exception, don't reassign the reference to roll back  
}
}
}

最新更新