Я в основном согласен с ответом Дэйва, но если вам нужно распределить процессорное время по всем «группам», то есть все группы задач должны развиваться параллельно, вы можете найти этот тип конструкции полезным (используя удаление в качестве «блокировки». работал нормально в моем случае, хотя я думаю, что это имеет тенденцию использовать больше памяти):
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;
}
}