Не понимаю пример кода spymemcached
Я использую клиент spymemcached для реализации моей логики кэширования. Почему-то мне нужно использовать CAS для одновременной модификации некоторого контента в кеше.
Я видел, что владелец уже показал очень хороший пример того, как использовать CASMutation здесь: http://code.google.com/p/spymemcached/wiki/Examples
Но у меня есть один вопрос по поводу этой части кода:
// Not strictly necessary if you specify the storage as
// LinkedList (our initial value isn't), but I like to keep
// things functional anyway, so I'm going to copy this list
// first.
LinkedList<Item> ll = new LinkedList<Item>(current);
Несмотря на то, что я внимательно читаю комментарии, я все еще не понимаю точно, что он пытается здесь сделать. Что если мы просто используем "current", не копируя в "ll"? Каковы потенциальные проблемы?
[ОБНОВИТЬ]
Я следую примеру кода и реализовал такой метод, будет ли это работать?
public <T> Set<T> addItemToSet(String key, int expire, final T newItem) throws Exception {
// This is how we modify a list when we find one in the cache.
CASMutation<Set<T>> mutation = new CASMutation<Set<T>>() {
// This is only invoked when a value actually exists.
public Set<T> getNewValue(Set<T> current) {
current.add( newItem );
return current;
}
};
HashSet<T> initialValue= new HashSet<T>();
initialValue.add( newItem );
CASMutator<Set<T>> mutator = new CASMutator<Set<T>>( memClient, getTranscoder() );
return mutator.cas(key, initialValue, expire, mutation);
}
Меня больше всего беспокоит, является ли это потокобезопасным.
1 ответ
Не используя библиотеку, я полагаю, что, если бы вы не копировали, в данном конкретном случае, вы получите исключение при попытке изменить Collections.singletonList()
, который является неизменным. Некоторые реализации List
просто не может быть изменено, и, как правило, предполагать, что это возможно, - плохая идея. (Было бы замечательно, если бы Java разделяла концепцию List
в качестве индексируемой читаемой последовательности и MutableList
подынтерфейс со всеми add
а также set
операции, ну да ладно).
В более широком смысле я даже не уверен, что это "не обязательно". Здесь происходит то, что вам дается существующий список элементов, и вас просят вернуть новое значение, которое будет использоваться, если условия CAS выполнены. Если вы измените список на месте, а затем вернетесь current
проблема в том, что вы потеряли обусловленность - текущий список был изменен (вами), даже если логика CAS означает, что предложенное вами новое значение будет отклонено.
Теперь, возможно, это на самом деле не имеет значения на практике, потому что логика библиотеки означает, что значение, фактически сохраненное в кэше, не обновляется; и изменение переходного состояния также не является проблемой, потому что после достаточного количества попыток ваше обновление будет успешным.
Но со всем этим я согласен, что нет никакой причины вообще не использовать функциональный подход - вам дают входной аргумент для чтения, и ожидается, что он вернет список, содержащий ваши модификации. Для ясности, надежности и рассуждений о программе гораздо лучше создать новый список с правильными значениями и вернуть его. В противном случае может сработать, а может и не сработать, но кто хочет писать код, семантика которого зависит от деталей реализации других библиотек, когда у вас есть возможность написать что-то однозначное?