Optimize TaskSet

The previous implementation of TaskSet was undesirable for a number of reasons:
simply to avoid the problem of concurrent access during StackDumps, it allocated
not only a new Set object each time tasks were added or removed, but also an
array. By copying every time the data structure was modified, this
implementation could take advantage of the fact that instance variable
modifications are "volatile" (in the Java sense) and provide some degree of
thread safety.

There's a much better approach we can use: locks :O

This implementation uses JRuby::Synchronized, a magical JRuby module which
effectively adds Java's "synchronized" to our class definition. This also lets
us take advantage of the fact that uncontended locks are cheap (Linux's futexes
are effectively "lock-free" when uncontended)

On MRI, the Set contant is bound to TaskSet, and we can depend on implementation
errata (i.e. the GIL o_O) to take care of synchronization for us.

This does leave the matter of Rubinius and other Ruby implementations like
IronRuby which don't have a GIL. I will consult with a few implementers of these
Rubies as to what the best solution is here.