グローバル静的オブジェクトを同期ロックとして定義します。
public static Object ConfirmationSynObj = new Object();
次の関数は私が書いたものですが、IllegalMonitorStateExceptionをスローします。
synchronized (Config.ConfirmationSynObj) {
new Thread(new Runnable() {
@Override
public void run() {
//this is a http request
appSignInfo = getAPKSignature(context, pkinfo.packageName);
Config.ConfirmationSynObj.notify();
}
}).start();
try {
Config.ConfirmationSynObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (appSignInfo == null) {
return ret;
}
}
並行性を防ぐためにオブジェクトまたは関数をロックする方法を知っている人はいますか?
wait
/notify
の一般的な置換はCountDownLatch
です。 (Java.util.concurrent
からも同様ですが、Semaphore
の逆の働きをします-トムの回答を参照してください)
必要なステップ数に初期化し、カウントダウンを終了したスレッドやその他の場所で、カウントダウンが0に達するのを待ちます。
void doFoo() {
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
//this is a http request
appSignInfo = getAPKSignature(context, pkinfo.packageName);
latch.countDown();
}
}).start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (appSignInfo == null) {
return ret;
}
}
しかし、そこで書いたコードは次のように簡略化できます。
void doFoo() {
return getAPKSignature(context, pkinfo.packageName);
}
何かをするために2番目のスレッドを開始し、その間に行うのは待つことだけです。そのタスクの実行中に何もすることがない場合は、余分なスレッドを作成しないでください。結果は同じです。
NetworkOnMainThreadExcpeption
を取得したためにUIスレッドの外部でHTTPリクエストを実行しようとすると、別の方法で実行する必要があります。 Androidは、コードをブロックしている間はコードを検出しませんが、たとえばAsyncTaskを使用します。
@Kayamanは私が知る限り正しく話しますが、謙虚に提案することができれば:Java.util.concurrent
あなたに多くの時間を節約することができます!
私が使用するのは セマフォ です。
ドキュメントから:「許可が利用可能になるまで、必要に応じて各acquire()ブロックを実行し、それを取得します。」.
しかし、他の選択肢もあります-あなたの場合のようにたくさんのピットフォールを避けるべきなので、可能な限りこれを使用することを強くお勧めします。
Semaphore semaphore = new Semaphore(0);
new Thread(new Runnable() {
@Override
public void run() {
//this is a http request
appSignInfo = getAPKSignature(context, pkinfo.packageName);
semaphore.release();
}
}).start();
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
上記のスレッドはConfirmationSynObj
オブジェクトのロックを所有していないため、IllegalMonitorStateException
をスローします
run
メソッド内でもう1つの同期ブロックを使用します
@Override
public void run() {
synchronized (Config.ConfirmationSynObj) {
//this is a http request
appSignInfo = getAPKSignature(context, pkinfo.packageName);
Config.ConfirmationSynObj.notify();
}
}
同期されたブロックでスレッドを作成して開始している可能性がありますが、スレッドがConfig.ConfirmationSynObj.notify();
になると、同期が行われていないことに気付くでしょう。
Run()内に同期ブロックを追加する必要があります。