#java #asynchronous #atomic #nonblocking #synchronized
#java #асинхронный #атомарный #неблокирующее #синхронизированный
Вопрос:
Вот предлагаемое решение (я искал то же самое — безуспешно)
public abstract class AsyncCache<T> {
/**
* an atomic int is used here only because stamped reference doesn't take a long,
* if it did the current thread could be used for the stamp.
*/
private AtomicInteger threadStamp = new AtomicInteger(1);
private AtomicStampedReference<T> reference = new AtomicStampedReference<T>(null, 0);
protected abstract T rebuild();
public void reset() {
reference.set(null, 0);
}
public T get() {
T obj = reference.getReference();
if (obj != null) return obj;
int threadID = threadStamp.incrementAndGet();
reference.compareAndSet(null, null, 0, threadID);
obj = rebuild();
reference.compareAndSet(null, obj, threadID, threadID);
return obj;
}
}
Процесс должен быть легко виден — ресурс создается только по запросу и становится недействительным при вызове reset .
Первый поток, запрашивающий ресурс, вставляет свой идентификатор в помеченную ссылку и затем вставит свою версию ресурса после создания, ЕСЛИ не будет вызван другой сброс. в случае последующего сброса первый запрашивающий поток вернет устаревшую версию ресурса (допустимый вариант использования), а некоторый запрос, запущенный после последнего сброса, заполнит ссылку своим результатом.
Пожалуйста, дайте мне знать, если я что-то пропустил или если есть лучшее (более быстрое простое элегантное) решение. Одна вещь — MAX_INT не обрабатывается намеренно — не верьте, что программа будет жить достаточно долго, но, безусловно, легко сделать.
Спасибо.
Комментарии:
1. Я не понимаю, что вы пытаетесь сделать. ThreadId и threadStamp кажутся (1) бесполезными и (2) неправильными, поскольку они фактически не будут соответствовать какому-либо потоку. Я не думаю, что AtomicStampedReference подходит, но опять же, я не уверен, что вы пытаетесь сделать.
Ответ №1:
Это явно не асинхронно, поскольку запрашивающий поток будет блокироваться до завершения метода rebuild(). Другая проблема — вы не проверяете значение, возвращаемое из compareAndSet . Я полагал, что вам нужно что-то вроде этого
if(reference.compareAndSet(null, null, 0, threadID)) { //if resource was already reseted - rebuild
reference.compareAndSet(null, obj, threadID, threadID);
obj = rebuild();
}
Но у этого подхода есть еще один недостаток — вам приходится перестраивать запись несколько раз (учитывая, что несколько потоков хотят эту запись одновременно). Вы можете использовать будущие задачи для этого случая (http://www.codercorp.com/blog/java/simple-concurrent-in-memory-cache-for-web-application-using-future.html ) или используйте MapMaker.
Комментарии:
1. 1-й — да — я предполагаю, что async в некотором смысле был неправильным — неблокирующее может описать это лучше.
2. 2nd — yes — FutureTask выглядит как раз тем, что было бы правильно — я знал, что что-то было, но не мог вспомнить это. 3-й — не нужно проверять результат compareAndSet — тот факт, что сброс был сброшен во время работы, в порядке — один пользователь получает слегка устаревший результат, в противном случае, возможно, придется ждать слишком долго. Спасибо за вашу помощь.