0

Сразу говорю, я новичок в написании многопоточных приложений, так что не судите строго:) У меня есть сервлет, в котором асинхронно производятся действия с базой данных. Ответ на http запрос будет готов только тогда, когда действия с базой данных будут произведены. В конце асинхронного метода onDataChange() вызывается метод responseReadyListener, который должен продолжить работу основного потока.

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
    //...
    //вызывается при завершении работы с базой данных
    responseReadyListener = new ResponseReadyListener() {
        @Override
        public void onResponseReady() {
            responseReady[0] = true;
            Log.info("onResponseReady");
            synchronized (this) {
                this.notify();
                Log.info("threadNotified");
            }
        }
    };

    ref.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            //асинхронный метод. После завершения работы с базой данных
            //вызывается onResponseReady(), который должен продолжить 
            //работу основного потока.
            responseReadyListener.onResponseReady();
        }
    });
    //основной поток, не должен завершаться пока responseReady[0] = false;
    while (!responseReady[0]) {
        Log.info("entered stopping loop");
        try {
            synchronized (this) {
                if (!responseReady[0]) {
                    Log.info("stoppingPerformed");
                    this.wait();
                }

            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    Log.info("respSent");
}

}

Все логи, которые у меня выполняются:

INFO: entered stopping loop
INFO: stoppingPerformed
INFO: onResponseReady
INFO: threadNotified

Далее больше ничего не выполняется, как будто зависает. В чем может быть проблема? Никаких эксепшенов нет.

Maxgmer
  • 2,798

1 Answers1

1

Подозреваю что проблема в синхронизации на разных объектах.

this во вложенном классе относится ко вложенному классу, в данном случае к анонимной реализации ResponseReadyListener:

//this здесь относится к анонимной реализации Listener
//а не к сервлету
//можете вывести this в лог для проверки.
synchronized (this) {
    this.notify();
    Log.info("threadNotified");
}

Исправить это можно обратившись к this родительского класса:

synchronized (<Имя класса-сервлета>.this) {
    <Имя класса-сервлета>.this.notify();
    Log.info("threadNotified");
}

либо выбрать какой-нибудь другой объект для синхронизации.

З.Ы. Также я не уверен, что изменения в responseReady будут доступны в родительском потоке. Я бы использовал вместо массива из одного элемента потокобезопасный класс, вроде AtomicBoolean.