Когда использовать синхронизированный в Java - PullRequest
10 голосов
/ 29 февраля 2012

Я надеюсь, что этой информации будет достаточно, так что вот так.Если вам нужна дополнительная информация, позвольте мне знать в комментариях.

У меня есть класс, который имеет два внутренних класса.Каждый из внутренних классов имеет два метода, которые вызывают метод во внешнем классе.Итак, это выглядит так:

public OuterClass {
    private boolean outerMethodHasBeenCalled = false;

    private void outerMethod() {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }

    private FirstInnerClass {
        public void someMethod() {
            outerMethod();
        }
    }

    private SecondInnerClass {
        public void someOtherMethod() {
            outerMethod();
        }
    }
}

Важно отметить, что:

  • Это для приложения для Android.Экземпляры FirstInnerClass и SecondInnerClass передаются в WebView в виде интерфейса JavaScript, поэтому someMethod и someOtherMethod можно вызывать в любое время, в произвольном порядке.
  • В настоящее время у меня возникла проблемас существующим кодом (без ключевого слова synchronized), где outerMethod вызывается в значительной степени в одно и то же время (я распечатываю сообщение журнала, и они помечаются с точностью до 1000-й секунды) различными объектами.Мое приложение затем «делает вещи» дважды, потому что outerMethodHasBeenCalled все еще ложно, когда вызывается outerMethod.Это не хорошо, и это именно то, что я пытаюсь предотвратить.Мое приложение должно «делать вещи» только один раз и только один раз: при первом вызове outerMethod.
  • Может показаться, что у меня есть несколько экземпляров OuterClass, но будьте уверены, что это только один экземплярOuterClass.

Важно, чтобы мое приложение «делало вещи» только при первом вызове outerMethod (надеюсь, это уже очевидно).Все последующие вызовы по существу игнорируются.Какой бы внутренний класс ни вызывал outerMethod первым - не имеет значения.

Итак, уместно ли в этом случае использовать ключевое слово synchronized?

Ответы [ 2 ]

19 голосов
/ 29 февраля 2012

Да, учитывая то, что вы выложили выше, я бы пошел с:

private synchronized void outerMethod() {
...
}

Обратите внимание, это будет иметь побочный эффект блокировки одного из вызывающих, пока не завершится externalMethod (). Если это приемлемо, круто. Если намерение состоит только в том, что код в outerMethod () запускается один раз, и , то нормально, чтобы второй вызывающий не задерживался, если первый вызывающий выполняет externalMethod (), вы могли бы рассмотреть:

public OuterClass {
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean();

    private void outerMethod() {
        if (outerMethodHasBeenCalled.compareAndSet(false, true)) {
            // do stuff
        }
    }
...

См. JavaDoc для AtomicBoolean , чтобы узнать, что там происходит (при условии, что оно доступно в Java на Android).

7 голосов
/ 29 февраля 2012

Оберните все в outerMethod, которое вы хотите запустить только один раз в синхронизированном блоке:

private void outerMethod() {
    synchronized (this) {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }
}

Таким образом, при первом вызове метода в синхронизированный будет разрешен только один потокблок за один раз.Первый выполнит код в операторе if, затем установит outerMethodHasBeenCalled в true.Другие потоки увидят, что это правда, и пропустят код if.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...