Java многопоточность, зависает сервлет

174
15 августа 2017, 13:30

Сразу говорю, я новичок в написании многопоточных приложений, так что не судите строго:) У меня есть сервлет, в котором асинхронно производятся действия с базой данных. Ответ на 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

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

Answer 1

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

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

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

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

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

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

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

READ ALSO
заменить русские буквы на английские java [требует правки]

заменить русские буквы на английские java [требует правки]

Не могу заменить русские буквы на английскиеНапример ,если я напишу я напишу "один" , программа должна вывести "odin"

317
Найти слова а потом их отсортировать

Найти слова а потом их отсортировать

Есть задание, где сначала надо вычислить слова с длинной слова больше среднего значения, a потом отсортировать их так, чтобы сначала шли слова...

187
Декомпиляция и обновление Android-приложения до Android M

Декомпиляция и обновление Android-приложения до Android M

Добрый день! Имеется старый проект QEMU for Android, который не обновлялся с 2010 года (то есть почти 8 лет)Соответственно, проект не имеет ни Runtime Permissions,...

256