「リソース マネージャ」クラスを含むマルチスレッド Java アプリケーションがあります。
このクラスには、初期化パラメーターとして要求できるリソースのリストが提供されます。次に、各ファイルのローカル ファイル システムをチェックし、ローカルであると判断されたファイルをリストに追加します。
クラスがリソース要求を受け取ると、次のいずれかが発生します。
リソースが (リスト内で) ローカルであると判断された場合: リソースが見つかる場所の URI を提供します。
リソースがリモート (リストにない) の場合: ワーカーがリソースを取得するようにスケジュールします。ワーカーは、タスクが完了するとマネージャーに通知し、ローカル リソース リストが更新されます。(リクエストスレッドは待機しません - そこにあるかどうかに関係なく)。
複数のスレッドがリソースを要求できるため、ReadWriteLock を使用してリスト アクセスを調整します。多くのスレッドがリストを同時に読み取ることができ、更新が必要な場合は writeLock が使用されます。
問題は、特定のリモート リソースのバックグラウンド ワーカーをスケジュールすることです。複数のスレッドが同じリソースのワーカーをスケジュールする場合、不必要なオーバーヘッドが必要になります (重複したタスクがこのケースをチェックするために完全に実行されない場合でも)。可能な限り最高の効率を達成するために、次の実装について疑問に思っています。
private final ReadWriteLock lock = new ReentrantReadWriteLock();
//assume each resource object has a volatile boolean "scheduled"
//with isScheduled() and setSheduled() setter/getter;
//assume the resource list is thread safe
public URI requestResource(Resource theResource){
URI resourceId = null;
//many threads can enter here
lock.readLock().lock();
try{
//if our resource is not in the list
if(!localResouces.contains(theResource)){
//double-check idiom...does it work here?
//if the resource isn't scheduled
if(!theResource.isScheduled()){
//only one thread may enter here
synchronized(this){
if(!theResource.isScheduled()){
//schedule task here...
theResource.setScheduled(true);
}
}
}
} else {
//its local, return the location
resouceId = theResource.getURI();
}
} finally {
lock.readLock().unlock();
}
//requesting object will deal with null value;
return resouceId;
}
ワーカーが終了すると、次のようになります。
public void update(Resource theResource){
//ensures no threads in the read block
lock.writeLock().lock();
try {
//update the list (would check result IRL, and not add if problem found)
localResources.add(theResource);
//set the scheduled field
theResource.setScheduled(false);
} finally {
lock.writeLock().unlock();
}
}
繰り返しますが、効率を最大化したいと思います。このケースに一致する例が見つかりませんでした。つまり、一般的な操作に高いスループットを許可しながら、最小限のブロッキング/オーバーヘッドでタスクをスケジュールできるようにします。
このアプローチにはどのような問題がありますか? 最初のメソッドは読み取りロックと同期の両方を取得する必要がありますが、isScheduled のチェックは読み取りブロック内にカプセル化されているため、更新メソッドは書き込みロックを取得するだけで済みます。これはスレッドセーフなスケジューリングとデータアクセスを提供しますか?
編集:
上記の方法をテストしたところ、正しい動作が見られました。これが実際に「スレッドセーフ」であるかどうかはまだわかりません。