Будучи впечатлен Guava вычислительная функция карты, я ищу своего рода "вычислительную ссылку" - ленивую реализацию ссылок на загрузку, которая параллельная Гуава простота использования, под которым я имею в виду, что она обрабатывает все операции блокировки, загрузки и обработки исключений под капотом, только подвергая метод get()
.
После краткого поиска ничего не появилось, я быстро перевернул свое собственное в качестве доказательства концепции:
public abstract class ComputingRef<T> implements Callable<T> {
private volatile T referent = null;
private Lock lock = new ReentrantLock();
public T get() {
T temp = referent;
if (temp == null) {
lock.lock();
try {
temp = referent;
if (temp == null) {
try {
referent = temp = call();
}
catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
else {
throw new RuntimeException(e);
}
}
}
}
finally {
lock.unlock();
}
}
return temp;
}
}
Этот ComputingRef
может быть анонимно расширен для реализации call()
, который функционирует как метод factory:
ComputingRef<MyObject> lazySingletonRef = new ComputingRef<MyObject>() {
@Override
public MyObject call() {
//fetch MyObject from database and return
}
};
Я не уверен, что эта реализация является оптимальной, но она демонстрирует, что мне нужно.
Позже я нашел этот пример из T2 Framework, который выглядит более сложным.
Теперь мои вопросы:
- Как можно улучшить код выше?
- Как он сравнивается с примером T2 и какие преимущества в этом примере могут быть более сложными?
- Существуют ли другие версии ленивой загрузки, которые я пропустил в моем поиске?
EDIT: Обновлена моя реализация, чтобы использовать локальную переменную, предложенную @irreputable answer - пожалуйста, повысьте ее, если вы найдете приведенный выше пример полезно.