Почему Synchronize вызывается в библиотеке Verlebx Handlebars? - PullRequest
0 голосов
/ 19 сентября 2018

Я пытаюсь понять, почему в этом методе используется блок synchronized из библиотеки рулей vertx io.vertx.ext.web.templ.handlebars.impl.HandlebarsTemplateEngineImpl class :

@Override
public void render(Map<String, Object> context, String templateFile, Handler<AsyncResult<Buffer>> handler) {
    try {
        int idx = templateFile.lastIndexOf('/');
        String prefix = "";
        String basename = templateFile;
        if (idx != -1) {
            prefix = templateFile.substring(0, idx);
            basename = templateFile.substring(idx + 1);
        }
        Template template = isCachingEnabled() ? cache.get(templateFile) : null;
        if (template == null) {
            synchronized (this) {
                loader.setPrefix(prefix);
                // Strip leading slash from Utils##normalizePath
                template = handlebars.compile(basename);
                if (isCachingEnabled()) {
                    cache.put(templateFile, template);
                }
            }
        }
        Context engineContext = Context.newBuilder(context).resolver(getResolvers()).build();
        handler.handle(Future.succeededFuture(Buffer.buffer(template.apply(engineContext))));
    } catch (Exception ex) {
        handler.handle(Future.failedFuture(ex));
    }
}

Пожалуйста, объясни мне, как будто я идиот!

1 Ответ

0 голосов
/ 20 сентября 2018

Во-первых, вопросы синхронизации никогда не являются "идиотскими" вопросами.
Я тоже потратил некоторое время на просмотр этого кода, но все еще не уверен на 100%, что он полностью правильный.

Основная причина иметь synchronized блок здесь предназначен для защиты следующих двух методов от выполнения не по порядку:

loader.setPrefix(prefix);
...
template = handlebars.compile(basename);

Видите ли, Handlebars имеет ссылку на загрузчик:

loader = new Loader(vertx);
...
handlebars = new Handlebars(loader);

Возможный сценарий без блока синхронизации будетбыть

T1 sets prefix to A and switches
T2 sets prefix to B and switches
T1 compiles template with prefix set to B, while thinking it's still A
...