15
15
*/
16
16
package rx .operators ;
17
17
18
+ import java .util .concurrent .ConcurrentLinkedQueue ;
19
+ import java .util .concurrent .atomic .AtomicInteger ;
20
+
18
21
import rx .Notification ;
19
22
import rx .Observer ;
20
23
import rx .Scheduler ;
21
- import rx .concurrency .Schedulers ;
22
24
import rx .util .functions .Action0 ;
23
25
24
26
/* package */ class ScheduledObserver <T > implements Observer <T > {
25
27
private final Observer <T > underlying ;
26
28
private final Scheduler scheduler ;
27
29
30
+ private final ConcurrentLinkedQueue <Notification <T >> queue = new ConcurrentLinkedQueue <Notification <T >>();
31
+ private final AtomicInteger counter = new AtomicInteger (0 );
32
+
28
33
public ScheduledObserver (Observer <T > underlying , Scheduler scheduler ) {
29
34
this .underlying = underlying ;
30
35
this .scheduler = scheduler ;
@@ -41,38 +46,50 @@ public void onError(final Exception e) {
41
46
}
42
47
43
48
@ Override
44
- public void onNext (final T v ) {
45
- enqueue (new Notification <T >(v ));
49
+ public void onNext (final T args ) {
50
+ enqueue (new Notification <T >(args ));
46
51
}
47
52
48
- private void enqueue (final Notification <T > notification ) {
53
+ private void enqueue (Notification <T > notification ) {
54
+ // this must happen before 'counter' is used to provide synchronization between threads
55
+ queue .offer (notification );
49
56
50
- Schedulers .currentThread ().schedule (new Action0 () {
57
+ // we now use counter to atomically determine if we need to start processing or not
58
+ // it will be 0 if it's the first notification or the scheduler has finished processing work
59
+ // and we need to start doing it again
60
+ if (counter .getAndIncrement () == 0 ) {
61
+ processQueue ();
62
+ }
63
+ }
64
+
65
+ private void processQueue () {
66
+ scheduler .schedule (new Action0 () {
51
67
@ Override
52
68
public void call () {
69
+ Notification <T > not = queue .poll ();
53
70
54
- scheduler .schedule (new Action0 () {
55
- @ Override
56
- public void call () {
57
- switch (notification .getKind ()) {
58
- case OnNext :
59
- underlying .onNext (notification .getValue ());
60
- break ;
61
- case OnError :
62
- underlying .onError (notification .getException ());
63
- break ;
64
- case OnCompleted :
65
- underlying .onCompleted ();
66
- break ;
67
- default :
68
- throw new IllegalStateException ("Unknown kind of notification " + notification );
71
+ switch (not .getKind ()) {
72
+ case OnNext :
73
+ underlying .onNext (not .getValue ());
74
+ break ;
75
+ case OnError :
76
+ underlying .onError (not .getException ());
77
+ break ;
78
+ case OnCompleted :
79
+ underlying .onCompleted ();
80
+ break ;
81
+ default :
82
+ throw new IllegalStateException ("Unknown kind of notification " + not );
69
83
70
- }
71
- }
72
- });
73
- }
84
+ }
74
85
75
- });
76
- };
86
+ // decrement count and if we still have work to do
87
+ // recursively schedule ourselves to process again
88
+ if (counter .decrementAndGet () > 0 ) {
89
+ scheduler .schedule (this );
90
+ }
77
91
92
+ }
93
+ });
94
+ }
78
95
}
0 commit comments