поиск предложений / критика для асинхронного восстановления ресурса

#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 — тот факт, что сброс был сброшен во время работы, в порядке — один пользователь получает слегка устаревший результат, в противном случае, возможно, придется ждать слишком долго. Спасибо за вашу помощь.