>> Actually, it just occurred to me that uniqueness, while not strictly
>> required, should certainly be encouraged. If you added the same task to a
>> ParallelTaskGroup's task sequence more than once, you'd basically get
>> serialized behavior, since only one thread could run the task at a time. So
>> perhaps a Group is actually appropriate.
>
> I think that really depends on the intent again. I agree that in many
> cases the supplied Tasks would not contain any duplicates, but is
> there a strong reason to actually enforce it rather than just document
> the behaviour?
I think the strongest argument for Group is that allowing duplicates could
result in confusing behavior. Making it a Group ensures that the intent is
clear.
>> Worse, TaskSequence executes sub-tasks by creating (or at least obtaining) a
>> new thread per task, which isn't really necessary. The same results could be
>> achieved by simply calling the synchronous version of execute() (the one
>> that doesn't take a listener argument) on each task in the list.
>
> This was part of the cause of my confusion with these classes. I
> didn't see why they needed to be Tasks themselves. It is
> straightforward to create and execute new Task if and when I want to,
> but I can't extract the executable portion of code from a Task once it
> is created. If the parallel execution code is wrapped in a Task, then
> that decision has been made for me.
That's true, and perhaps it is reasonable to consider making TaskGroup a
non-Task class. OTOH, if such a class is not wrapped in a Task, the calling
thread will block while it waits for the sub-tasks to complete, which may not
be the desired behavior. If the 90% case is that a TaskGroup is run in its own
Task, then maybe it should actually be a Task.
> Do you remember if it was a conscious choice for these classes to
> extend Task from the outset, or do they do so because they use
> TaskListener for notifications?
I think they just seemed like a natural fit for a Task - TaskGroup allows a
caller to create a task hierarchy in the same way that Component and Container
create a UI hierarchy.
The idea of using a static execute() method to launch parallel tasks is
interesting:
public class TaskGroup {
public static void execute(Sequence<Task> tasks, ExecutorService
executorService) { ... }
public static void execute(Sequence<Task> tasks, TaskListener listener,
ExecutorService executorService) { ... }
}
If I understand your suggestion correctly, the first version would basically do
what TaskGroup#execute() does now. The second version would wrap a call to the
first version in a Task (probably implemented as a static inner class) and
basically do what TaskGroup#execute(TaskListener, ExecutorService) does now. Is
that correct?
If so, I could go either way. I'm not sure which would be clearer to most
developers - a dedicated TaskGroup class that extends Task, or these static
methods. I'm inclined to think the former, but maybe that is just personal
preference.
G