私の Android アプリには、効果的に生産者/消費者の関係にある 2 つのスレッドがあります。プロデューサ スレッド (Thread のサブクラス) はバッファにオブジェクトを設定し、コンシューマ スレッド (AsyncTask のサブクラス) はそのバッファで動作します。ここのJava保護ロック同時実行チュートリアルから、「サードパーティ」スレッドを使用してこの交換を調整できることを収集しますが、理想的には、待機の呼び出しを介して消費者スレッド自体をシャットダウンできるようにしたいと考えています。本当のタスクは、プロデューサーによってデータが取り込まれた後にバッファを操作することだけです。プロデューサーは、プロデューサーがバッファーへの入力を完全に終了したときにのみ、notify または notifyAll の呼び出しを介してそれを起こします。これを容易にするために、コンシューマーとプロデューサーにそれぞれ次の構成を使用しています。
コンシューマ.java
public class Consumer extends AsyncTask<Object,Integer,Object>{
private String TAG = "Consumer";
private String SUBCLASS_TAG = "";
private String FUNCTION_TAG = "";
private int UUID = MasterSemaphore.getAndIncrementUuidTracker();
public synchronized void getMonitorForNotification(){
FUNCTION_TAG = "::getMonitorForNotification";
while(MasterSemaphore.getIsBufferingMap().get(UUID)){
try {
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "about to wait...");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
FUNCTION_TAG = "::getMonitorForNotification";
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "Received notification!");
}
@Override
protected Object doInBackground(Object... bgTaskResources) {
Producer hProducer = (Producer)bgTaskResources[0];
//The next call is supposed to freeze this thread's execution via an invocation
//of wait-- see the Producer::populateBuffer(...) method
hProducer.populateBuffer(5,this);
//...handle other AsyncTask callbacks
Producer.java
//..snip
public synchronized int populateBuffer(int numElements, Consumer externalTaskCaller){
TAG = "Producer"
SUBCLASS_TAG = "";
FUNCTION_TAG = "::populateBuffer";
//First set the bufferingMap over the external caller's UUID to true
MasterSemaphore.getIsBufferingMap().put(externalTaskCaller.getUUID(), true);
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just set "+externalTaskCaller.getUUID()+" Key in
the bufferingMap to true");
//Next acquire the monitor of the external caller, and tell it to wait for notification
externalTaskCaller.getMonitorForNotification();
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just acquired a monitor lock on
externalCaller"+externalTaskCaller.toString()+", hopefully");
int elementsProduced = 0;
for (int i=0;i<numElements;i++){
mvElemVector.add(new Element());
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just created element number "+i+" of
"+numElements);
elementsProduced++;
}
if(externalTaskCaller != null){
MasterSemaphore.getIsBufferingMap().put(externalTaskCaller.getUUID(), false);
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just set "+externalTaskCaller.getUUID()+" Key
in the bufferingMap to false since our buffer writing is done");
externalTaskCaller.notifyAll();
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just notified the external caller
"+externalTaskCaller.toString());
}
return threadsProduced;
}
//..snip
この機能に対して単体テストを実行したときに表示される結果 (基本的には、プロデューサー スレッドを作成して開始し、コンシューマー タスクを作成して実行するだけです) は、ログ エントリのみを返します。
01-02 09:01:53.530: I/Producer::populateBuffer(21932): just set 0 Key in the
bufferingMap to true
01-02 09:01:53.530:I/Consumer::getMonitorForNotification(21932): about to wait...
それだけです...
externalTaskCaller.getMonitorForNotification();
しかし決して届かない
Log.i(TAG+SUBCLASS_TAG+FUNCTION_TAG, "just acquired a monitor lock on
externalCaller"+externalTaskCaller.toString()+", hopefully");
ここでの待機通知の実装の何が問題になっていますか? リンクされたチュートリアルの Drop オブジェクトのような「サードパーティ」オブジェクトは、生産者/消費者交換を調整するために必要ですか?