Транзакционно изменять записи в коллекции - PullRequest
0 голосов
/ 22 октября 2018

У меня есть этот код:

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();
    }
}

Объяснение:

  • Есть карта объектов (ключи - строки).

  • В одной теме эта Карта заполнена объектами.

  • В другой теме некоторые (не все) объекты должны быть изменены.При изменении объекта может быть сгенерировано некоторое исключение (в случае выше это моделируется в методе "changeObject").В случае исключения объект не должен добавляться на карту.

Дело в том, что добавление всех объектов на карте должно быть транзакционным.Может быть, я не использую здесь точное слово, поэтому я объясняю: в конце либо все записи должны быть изменены, либо ни одна из них не должна быть изменена.

Так что вопрос: можно ли это достичь?Как должен выглядеть метод "changeCollection"?

В настоящее время я использую следующее решение: я создаю временную карту, заполняю ее клонами записей с основной карты, пытаюсь изменить записи клонов на этой временной карте, и в случае, еслииз-за отсутствия исключений я делаю переменную основной карты, чтобы указывать на объект временной карты.Мне не нравится это решение, и я предпочитаю решение без клонов, если оно существует.

Другое дело: я не хочу, чтобы у вас были какие-либо внешние библиотеки.

1 Ответ

0 голосов
/ 22 октября 2018

Да, это может быть достигнуто.Пожалуйста, посмотрите на приведенный ниже фрагмент.

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  
        }
    }

}
...