I would suggest the start method is moved. The one downside to the initalizer
approach is that from within the initalizer you will not be able to set final
fields.
Also, a good rule of thumb is to not expose objects to other threads until the
constructor returns. Looking in the JLS 17.5 there are the following lines:
"The detailed semantics of final fields are somewhat different from those of
normal fields. In particular, compilers have a great deal of freedom to move
reads of final fields across synchronization barriers and calls to arbitrary or
unknown methods. Correspondingly, compilers are allowed to keep the value of a
final field cached in a register and not reload it from memory in situations
where a non-final field would have to be reloaded."
and the comment:
"An object is considered to be completely initialized when its constructor
finishes. A thread that can only see a reference to an object after that object
has been completely initialized is guaranteed to see the correctly initialized
values for that object's final fields."
The implications (as I read it - and I am by no means an expert) is that even
with locking and other thread safe actions the only way to be sure final fields
will be properly visible is after the completion of the constructor. Any time
earlier then that you are left exposed to the whims compiler and caching
performed by the cpu.
We could provide a smarter start method and have it return the executor itself.
I.e: public Executor start()
{ super.start(); return this; }
By doing this you
can chain the constructor and the start in a nice compact manner:
executors.add(new Executor(...).start()); which is what this feels like it was
trying to do by placing start at the end of the constructor.
Right. The parent build needs to be run outside of the normal executors so that
it can let child builds use that executor.
In the mean time, a work around is to tie the parent build to somewhere where
more executors are available.