Я наткнулся на приведенный ниже код, и мне интересно, делает ли он именно то, что я думаю:
synchronized(sObject) {
mShouldExit = true;
sObject.notifyAll()
while (!mExited) {
try {
sObject.wait();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
О контексте: есть другой поток, который проверяет mShouldExit
(внутри монитора sObject
) и в этом случае завершается.
Мне кажется, это неправильный шаблон. Если произойдет прерывание, он снова установит статус прерывания, поэтому, когда он вернется к sObject.wait()
, появится еще одно InterruptedException и т. д. и т. д. и т. д. Следовательно, он никогда не сможет перейти в действительное состояние ожидания. ( sObject.wait()
), то есть он никогда не освободит монитор sObject
. Это может привести к бесконечному циклу, так как другой поток не может установить для mExiting значение true, потому что он никогда не сможет войти в монитор sObject. (Поэтому я думаю, что вызов interrupt()
является ошибкой, его нельзя здесь использовать.) Я что-то упустил?
Обратите внимание, что фрагмент кода является частью официального исходного кода платформы Android.
ОБНОВЛЕНИЕ:на самом деле ситуация еще хуже, потому что тот же шаблон используется в Android, когда начинается рендеринг GL. Официальный исходный код GLSurfaceView.GLThread.surfaceCreated()
:
public void surfaceCreated() {
synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
sGLThreadManager.notifyAll();
while((mWaitingForSurface) && (!mExited)) {
try {
sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
Вы можете воспроизвести ошибку аналогичным образом: убедитесь, что ваш UI-поток все еще имеет флаг прерванного состояния, затем добавьте свой GLSurfaceView и запустите визуализацию GL (через setRenderer(.. .)
, но на некоторых устройствах убедитесь, что ваш GLSurfaceView имеет статус Visibility.VISIBLE
, иначе рендеринг не начнется).
Если вы выполните описанные выше шаги, ваш поток пользовательского интерфейса зациклится, потому что приведенный выше код будет продолжать генерировать InterruptedException
(из-за wait()
) и поэтому поток GL никогда не сможет установить mWaitingForSurface
в false.
Согласно моим тестам, похоже, что такой бесконечный цикл также приведет к бесконечной последовательности сборки мусора GC_CONCURRENT(или, по крайней мере, к таким сообщениям в logcat). Интересно, у кого-то ранее была неизвестная плохо определенная проблема в stackoverflow, которая может быть связана: Как решить проблему освобождения GC_concurrent?
Возможно ли, что флаг прерывания его потока пользовательского интерфейса был установлен в значение true, и он использовал GLSurfaceView для карты, которую он упоминает? Просто предположение, возможный сценарий.