私は Dave の答えにほぼ同意しますが、CPU 時間をすべての「グループ」にわたってスライスする必要がある場合、つまりすべてのタスク グループが並行して進行する必要がある場合は、この種の構造が役立つ場合があります (削除を「ロック」として使用します。私の場合は、より多くのメモリを使用する傾向があると思いますが):
class TaskAllocator {
private final ConcurrentLinkedQueue<Queue<Runnable>> entireWork
= childQueuePerTaskGroup();
public Queue<Runnable> lockTaskGroup(){
return entireWork.poll();
}
public void release(Queue<Runnable> taskGroup){
entireWork.offer(taskGroup);
}
}
と
class DoWork implmements Runnable {
private final TaskAllocator allocator;
public DoWork(TaskAllocator allocator){
this.allocator = allocator;
}
pubic void run(){
for(;;){
Queue<Runnable> taskGroup = allocator.lockTaskGroup();
if(task==null){
//No more work
return;
}
Runnable work = taskGroup.poll();
if(work == null){
//This group is done
continue;
}
//Do work, but never forget to release the group to
// the allocator.
try {
work.run();
} finally {
allocator.release(taskGroup);
}
}//for
}
}
その後、最適な数のスレッドを使用してDoWork
タスクを実行できます。ラウンド ロビンの負荷分散のようなものです。
単純なキューの代わりにこれを使用することで、より洗練された何かを行うこともできますTaskAllocator
(より多くのタスクが残っているタスク グループが実行される傾向があります)。
ConcurrentSkipListSet<MyQueue<Runnable>> sophisticatedQueue =
new ConcurrentSkipListSet(new SophisticatedComparator());
どこSophisticatedComparator
ですか
class SophisticatedComparator implements Comparator<MyQueue<Runnable>> {
public int compare(MyQueue<Runnable> o1, MyQueue<Runnable> o2){
int diff = o2.size() - o1.size();
if(diff==0){
//This is crucial. You must assign unique ids to your
//Subqueue and break the equality if they happen to have same size.
//Otherwise your queues will disappear...
return o1.id - o2.id;
}
return diff;
}
}