1515 */
1616package rx .internal .schedulers ;
1717
18- import java .util .ArrayList ;
19- import java .util .List ;
2018import java .util .concurrent .Future ;
21- import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
19+ import java .util .concurrent .atomic .AtomicBoolean ;
20+ import java .util .concurrent .atomic .AtomicReference ;
2221
2322import rx .Subscription ;
24- import rx .exceptions .CompositeException ;
2523import rx .exceptions .OnErrorNotImplementedException ;
2624import rx .functions .Action0 ;
2725import rx .plugins .RxJavaPlugins ;
3129 * A {@code Runnable} that executes an {@code Action0} and can be cancelled. The analog is the
3230 * {@code Subscriber} in respect of an {@code Observer}.
3331 */
34- public final class ScheduledAction implements Runnable , Subscription {
35- final Subscription [] cancel ;
36- volatile int count ;
32+ public final class ScheduledAction extends AtomicReference <Thread > implements Runnable , Subscription {
33+ /** */
34+ private static final long serialVersionUID = -3962399486978279857L ;
35+ final CompositeSubscription cancel ;
3736 final Action0 action ;
38- /** Set by the run() method to avoid self interrupting at the end of the run method. */
39- Thread runner ;
4037
4138 public ScheduledAction (Action0 action ) {
4239 this .action = action ;
43- this .cancel = new Subscription [ 4 ] ;
40+ this .cancel = new CompositeSubscription () ;
4441 }
4542
4643 @ Override
4744 public void run () {
48- Thread thread = Thread .currentThread ();
4945 try {
50- runner = thread ;
46+ lazySet ( Thread . currentThread ()) ;
5147 action .call ();
5248 } catch (Throwable e ) {
5349 // nothing to do but print a System error as this is fatal and there is nowhere else to throw this
@@ -58,6 +54,7 @@ public void run() {
5854 ie = new IllegalStateException ("Fatal Exception thrown on Scheduler.Worker thread." , e );
5955 }
6056 RxJavaPlugins .getInstance ().getErrorHandler ().handleError (ie );
57+ Thread thread = Thread .currentThread ();
6158 thread .getUncaughtExceptionHandler ().uncaughtException (thread , ie );
6259 } finally {
6360 unsubscribe ();
@@ -66,76 +63,24 @@ public void run() {
6663
6764 @ Override
6865 public boolean isUnsubscribed () {
69- return count < 0 ;
66+ return cancel . isUnsubscribed () ;
7067 }
7168
7269 @ Override
7370 public void unsubscribe () {
74- Subscription [] subs = cancel ;
75- if (count >= 0 ) {
76- synchronized (this ) {
77- if (count < 0 ) {
78- return ;
79- }
80- count = -1 ;
81- }
71+ if (!cancel .isUnsubscribed ()) {
72+ cancel .unsubscribe ();
8273 }
83- unsubscribeFromAll (subs );
8474 }
8575
86-
8776 /**
8877 * Adds a general Subscription to this {@code ScheduledAction} that will be unsubscribed
8978 * if the underlying {@code action} completes or the this scheduled action is cancelled.
9079 *
9180 * @param s the Subscription to add
9281 */
9382 public void add (Subscription s ) {
94- if (count >= 0 ) {
95- synchronized (this ) {
96- int c = count ;
97- if (c >= 0 ) {
98- cancel [c ] = s ;
99- count = c + 1 ;
100- return ;
101- }
102- }
103- }
104- s .unsubscribe ();
105- }
106-
107- private static void unsubscribeFromAll (Subscription ... subscriptions ) {
108- if (subscriptions == null ) {
109- return ;
110- }
111- List <Throwable > es = null ;
112- for (Subscription s : subscriptions ) {
113- if (s == null ) {
114- break ;
115- }
116- try {
117- s .unsubscribe ();
118- } catch (Throwable e ) {
119- if (es == null ) {
120- es = new ArrayList <Throwable >();
121- }
122- es .add (e );
123- }
124- }
125- if (es != null ) {
126- if (es .size () == 1 ) {
127- Throwable t = es .get (0 );
128- if (t instanceof RuntimeException ) {
129- throw (RuntimeException ) t ;
130- } else {
131- throw new CompositeException (
132- "Failed to unsubscribe to 1 or more subscriptions." , es );
133- }
134- } else {
135- throw new CompositeException (
136- "Failed to unsubscribe to 2 or more subscriptions." , es );
137- }
138- }
83+ cancel .add (s );
13984 }
14085
14186 /**
@@ -144,7 +89,7 @@ private static void unsubscribeFromAll(Subscription... subscriptions) {
14489 * @param f the future to add
14590 */
14691 public void add (final Future <?> f ) {
147- add (new FutureCompleter (f ));
92+ cancel . add (new FutureCompleter (f ));
14893 }
14994
15095 /**
@@ -155,7 +100,7 @@ public void add(final Future<?> f) {
155100 * the parent {@code CompositeSubscription} to add
156101 */
157102 public void addParent (CompositeSubscription parent ) {
158- add (new Remover (this , parent ));
103+ cancel . add (new Remover (this , parent ));
159104 }
160105
161106 /**
@@ -173,7 +118,7 @@ private FutureCompleter(Future<?> f) {
173118
174119 @ Override
175120 public void unsubscribe () {
176- if (runner != Thread .currentThread ()) {
121+ if (ScheduledAction . this . get () != Thread .currentThread ()) {
177122 f .cancel (true );
178123 } else {
179124 f .cancel (false );
@@ -186,13 +131,11 @@ public boolean isUnsubscribed() {
186131 }
187132
188133 /** Remove a child subscription from a composite when unsubscribing. */
189- private static final class Remover implements Subscription {
134+ private static final class Remover extends AtomicBoolean implements Subscription {
135+ /** */
136+ private static final long serialVersionUID = 247232374289553518L ;
190137 final Subscription s ;
191138 final CompositeSubscription parent ;
192- @ SuppressWarnings ("unused" )
193- volatile int once ;
194- static final AtomicIntegerFieldUpdater <Remover > ONCE_UPDATER
195- = AtomicIntegerFieldUpdater .newUpdater (Remover .class , "once" );
196139
197140 public Remover (Subscription s , CompositeSubscription parent ) {
198141 this .s = s ;
@@ -206,7 +149,7 @@ public boolean isUnsubscribed() {
206149
207150 @ Override
208151 public void unsubscribe () {
209- if (ONCE_UPDATER . compareAndSet (this , 0 , 1 )) {
152+ if (compareAndSet (false , true )) {
210153 parent .remove (s );
211154 }
212155 }
0 commit comments