15
15
*/
16
16
package rx .internal .schedulers ;
17
17
18
+ import java .util .concurrent .Future ;
18
19
import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
19
20
20
21
import rx .Subscription ;
21
22
import rx .exceptions .OnErrorNotImplementedException ;
22
23
import rx .functions .Action0 ;
23
24
import rx .plugins .RxJavaPlugins ;
24
25
import rx .subscriptions .CompositeSubscription ;
26
+ import rx .subscriptions .Subscriptions ;
25
27
26
28
/**
27
29
* A {@code Runnable} that executes an {@code Action0} and can be cancelled. The analog is the
@@ -33,6 +35,8 @@ public final class ScheduledAction implements Runnable, Subscription {
33
35
volatile int once ;
34
36
static final AtomicIntegerFieldUpdater <ScheduledAction > ONCE_UPDATER
35
37
= AtomicIntegerFieldUpdater .newUpdater (ScheduledAction .class , "once" );
38
+ /** Set by the run() method to avoid self interrupting at the end of the run method. */
39
+ volatile Thread runner ;
36
40
37
41
public ScheduledAction (Action0 action ) {
38
42
this .action = action ;
@@ -42,6 +46,7 @@ public ScheduledAction(Action0 action) {
42
46
@ Override
43
47
public void run () {
44
48
try {
49
+ runner = Thread .currentThread ();
45
50
action .call ();
46
51
} catch (Throwable e ) {
47
52
// nothing to do but print a System error as this is fatal and there is nowhere else to throw this
@@ -72,15 +77,24 @@ public void unsubscribe() {
72
77
}
73
78
74
79
/**
75
- * @warn javadoc missing
80
+ * Adds a general Subscription to this {@code ScheduledAction} that will be unsubscribed
81
+ * if the underlying {@code action} completes or the this scheduled action is cancelled.
76
82
*
77
- * @param s
78
- * @warn param "s" undescribed
83
+ * @param s the Subscription to add
79
84
*/
80
85
public void add (Subscription s ) {
81
86
cancel .add (s );
82
87
}
83
88
89
+ /**
90
+ * Adds the given Future to the unsubscription composite in order to support
91
+ * cancelling the underlying task in the executor framework.
92
+ * @param f the future to add
93
+ */
94
+ public void add (final Future <?> f ) {
95
+ cancel .add (Subscriptions .create (new FutureCompleter (f )));
96
+ }
97
+
84
98
/**
85
99
* Adds a parent {@link CompositeSubscription} to this {@code ScheduledAction} so when the action is
86
100
* cancelled or terminates, it can remove itself from this parent.
@@ -92,10 +106,32 @@ public void addParent(CompositeSubscription parent) {
92
106
cancel .add (new Remover (this , parent ));
93
107
}
94
108
109
+ /**
110
+ * Cancels the captured future if the caller of the call method
111
+ * is not the same as the runner of the outer ScheduledAction to
112
+ * prevent unnecessary self-interrupting if the unsubscription
113
+ * happens from the same thread.
114
+ */
115
+ private final class FutureCompleter implements Action0 {
116
+ private final Future <?> f ;
117
+
118
+ private FutureCompleter (Future <?> f ) {
119
+ this .f = f ;
120
+ }
121
+
122
+ @ Override
123
+ public void call () {
124
+ if (runner != Thread .currentThread ()) {
125
+ f .cancel (true );
126
+ }
127
+ }
128
+ }
129
+
95
130
/** Remove a child subscription from a composite when unsubscribing. */
96
131
private static final class Remover implements Subscription {
97
132
final Subscription s ;
98
133
final CompositeSubscription parent ;
134
+ @ SuppressWarnings ("unused" )
99
135
volatile int once ;
100
136
static final AtomicIntegerFieldUpdater <Remover > ONCE_UPDATER
101
137
= AtomicIntegerFieldUpdater .newUpdater (Remover .class , "once" );
0 commit comments