Scheduler Improvements 507

NewThread/EventLoop scheduler improvements proposal.

**NewThreadScheduler**

There is no need to have an ```innerSubscription``` there as the underlying Executor knows what tasks are in its queue and a ```shutdown``` will cancel them anyway. In the original version, I made a small mistake by leaving out an ```innerSubscription.add(s)``` which was one of the main contribution to the speed improvements (did not affect correctness).

**EventLoopScheduler**

An EventLoopScheduler needs to track its tasks so it can selectively cancel them in the NewThreadScheduler. Since an ELS worker is single threaded, the addition and removal of the completed tasks are more like queue operations; adding a last item and removing a first item in CompositeSubscription can be expensive even if the size is small due to the copying and state machine overhead. 

**SubscriptionQueue**

Therefore, I've built a special array-based (ringbuffer) queue called ```SubscriptionQueue``` which can resize itself as needed, similar to ArrayDeque, but behaves like a composite and queued items can be unsubscribed at once and provides the usual cancellation policy. When benchmarked with a simple loop of add/remove pair, it gives ~ 532 Mops/s whereas ```CompositeSubscription``` gives 16 Mops/s. It uses ```synchronized``` as generally one needs to synchronize the producer(s) of tasks with the completion of the tasks on the worker thread, where the producer count is likely small. The initial queue capacity is 8 which favors fast tasks and the array fits nicely into a typical 64 byte cache line. One unique property is that it dequeues based on object identity and not the head of the queue. The reason for this is that when there are multiple producers, queueing their subscriptions might happen in different order than their tasks are scheduled (i.e., the head of the queue points to s1 while t2 gets scheduled first).

**Perf tests**

I did some perf testing with ```ComputationSchedulerPerf``` but I ran into some trouble: the initial 512M memory for the benchmark doesn't seem to be enough, especially on a 4/8 core machine. Both the master and this PR goes really slow or fails with GC errors because the internal queues of the Executors get flooded with tasks. Each task is about 650 byte and having tens of thousands queued up consumes lot of memory. I run the perftests with 1300M which was enough although still pounding on the GC. (Btw, I don't understand the perf code: does the subscribeOn test do 1M one-time subscription, or subscribes to a stream of 1M elements? If the latter, what are the tasks that hammer the executor?)

*Master* (https://gist.github.com/akarnokd/1fe0fb74f896c48c61a8)
```
Benchmark                                   (size)   Mode   Samples         Mean   Mean error    Units
r.s.ComputationSchedulerPerf.observeOn           1   avgt         5     1944,238       64,954    ns/op
r.s.ComputationSchedulerPerf.observeOn        1024   avgt         5   119353,236     1968,424    ns/op
r.s.ComputationSchedulerPerf.observeOn     1048576   avgt         5 129596502,875 11464347,421    ns/op
r.s.ComputationSchedulerPerf.subscribeOn         1   avgt         5     1659,862      462,385    ns/op
r.s.ComputationSchedulerPerf.subscribeOn      1024   avgt         5  4643038,650 39587231,914    ns/op
r.s.ComputationSchedulerPerf.subscribeOn   1048576   avgt         5   317353,904   566003,080    ns/op
```

**This proposal** (https://gist.github.com/akarnokd/6d9ba66761c5bdb8ecd7)
```
Benchmark                                   (size)   Mode   Samples         Mean   Mean error    Units
r.s.ComputationSchedulerPerf.observeOn           1   avgt         5     1858,486       73,600    ns/op
r.s.ComputationSchedulerPerf.observeOn        1024   avgt         5   117680,475     2305,467    ns/op
r.s.ComputationSchedulerPerf.observeOn     1048576   avgt         5 129298288,453 14093401,564    ns/op
r.s.ComputationSchedulerPerf.subscribeOn         1   avgt         5      839,078      293,626    ns/op
r.s.ComputationSchedulerPerf.subscribeOn      1024   avgt         5    51253,754   150446,345    ns/op
r.s.ComputationSchedulerPerf.subscribeOn   1048576   avgt         5   371325,179   692740,819    ns/op
```

The ObserveOn test benefits minimally from the changes.  For the 1 onSubscribe, it drops to 840ns. For the other sizes, I suspect hectic GC overhead so I can't declare a winner.

(Generally, since we use a lot of AtomicXYZ classes, they add 24 bytes to the memory footprint every time a Subscription is present. In order to get rid of them, one would need to replace it with volatile fields and ```Unsafe``` calls to get the CAS functionality back.)

Benchmarked on an i7 920 @ 2.66GHz, 4/8 hyperthreaded cores, 6GB total RAM, Windows 7 x64, Java 7u55 x64.