私は以下のコードに出くわしました、そしてそれが私が思うことを正確に行うかどうか疑問に思っています:
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
モニターを解放することはありません。他のスレッドはsObjectのモニターに入ることができないため、mExitingをtrueに設定できないため、これにより無限ループが発生する可能性があります。(したがって、この呼び出しはエラーだと思いinterrupt()
ます。ここでは使用しないでください。)何かが足りないのでしょうか。
コードスニペットは、公式のAndroidフレームワークソースコードの一部であることに注意してください。
更新:実際には、GLレンダリングの開始時にAndroidで同じパターンが使用されるため、状況はさらに悪化します。の公式ソースコード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
ステータスがあることを確認してください。そうでない場合、レンダリングは行われません。始める)。
上記の手順に従うと、UIスレッドは無限ループになります。これは、上記のコードがInterruptedException
(のために)を生成し続けるため、GLスレッドがfalsewait()
に設定されることはないためです。mWaitingForSurface
私のテストによると、このような無限ループは、GC_CONCURRENTガベージコレクション(または、少なくともlogcat内のこのようなメッセージ)の無限シーケンスをもたらすようです。興味深いことに、誰かが以前にスタックオーバーフローに関する未知の不十分に定義された問題を抱えていました。これは関連している可能性があります: 解放されたGC_concurrentを解決する方法は?
彼のUIスレッドの割り込みフラグがtrueに設定されていて、彼が言及しているマップにGLSurfaceViewを使用していた可能性はありませんか?単なる仮定、考えられるシナリオ。