@@ -64,7 +64,7 @@ private Observer<String> serializedObserver(Observer<String> o) {
64
64
@ Test
65
65
public void testSingleThreadedBasic () {
66
66
Subscription s = mock (Subscription .class );
67
- TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable (s , "one" , "two" , "three" );
67
+ TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable ("one" , "two" , "three" );
68
68
Observable <String > w = Observable .create (onSubscribe );
69
69
70
70
Observer <String > aw = serializedObserver (observer );
@@ -84,8 +84,7 @@ public void testSingleThreadedBasic() {
84
84
85
85
@ Test
86
86
public void testMultiThreadedBasic () {
87
- Subscription s = mock (Subscription .class );
88
- TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable (s , "one" , "two" , "three" );
87
+ TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable ("one" , "two" , "three" );
89
88
Observable <String > w = Observable .create (onSubscribe );
90
89
91
90
BusyObserver busyObserver = new BusyObserver ();
@@ -109,8 +108,7 @@ public void testMultiThreadedBasic() {
109
108
110
109
@ Test (timeout = 1000 )
111
110
public void testMultiThreadedWithNPE () throws InterruptedException {
112
- Subscription s = mock (Subscription .class );
113
- TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable (s , "one" , "two" , "three" , null );
111
+ TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable ("one" , "two" , "three" , null );
114
112
Observable <String > w = Observable .create (onSubscribe );
115
113
116
114
BusyObserver busyObserver = new BusyObserver ();
@@ -141,40 +139,40 @@ public void testMultiThreadedWithNPE() throws InterruptedException {
141
139
142
140
@ Test
143
141
public void testMultiThreadedWithNPEinMiddle () {
144
- Subscription s = mock (Subscription .class );
145
- TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable (s , "one" , "two" , "three" , null , "four" , "five" , "six" , "seven" , "eight" , "nine" );
146
- Observable <String > w = Observable .create (onSubscribe );
147
-
148
- BusyObserver busyObserver = new BusyObserver ();
149
- Observer <String > aw = serializedObserver (busyObserver );
150
-
151
- w .subscribe (aw );
152
- onSubscribe .waitToFinish ();
153
-
154
- System .out .println ("OnSubscribe maxConcurrentThreads: " + onSubscribe .maxConcurrentThreads .get () + " Observer maxConcurrentThreads: " + busyObserver .maxConcurrentThreads .get ());
155
-
156
- // we can have concurrency ...
157
- assertTrue (onSubscribe .maxConcurrentThreads .get () > 1 );
158
- // ... but the onNext execution should be single threaded
159
- assertEquals (1 , busyObserver .maxConcurrentThreads .get ());
160
-
161
- // this should not be the full number of items since the error should stop it before it completes all 9
162
- System .out .println ("onNext count: " + busyObserver .onNextCount .get ());
163
- assertTrue (busyObserver .onNextCount .get () < 9 );
164
- assertTrue (busyObserver .onError );
165
- // no onCompleted because onError was invoked
166
- assertFalse (busyObserver .onCompleted );
167
- // non-deterministic because unsubscribe happens after 'waitToFinish' releases
168
- // so commenting out for now as this is not a critical thing to test here
169
- // verify(s, times(1)).unsubscribe();
142
+ int n = 10 ;
143
+ for (int i = 0 ; i < n ; i ++) {
144
+ TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable ("one" , "two" , "three" , null ,
145
+ "four" , "five" , "six" , "seven" , "eight" , "nine" );
146
+ Observable <String > w = Observable .create (onSubscribe );
147
+
148
+ BusyObserver busyObserver = new BusyObserver ();
149
+ Observer <String > aw = serializedObserver (busyObserver );
150
+
151
+ w .subscribe (aw );
152
+ onSubscribe .waitToFinish ();
153
+
154
+ System .out .println ("OnSubscribe maxConcurrentThreads: " + onSubscribe .maxConcurrentThreads .get () + " Observer maxConcurrentThreads: " + busyObserver .maxConcurrentThreads .get ());
155
+
156
+ // we can have concurrency ...
157
+ assertTrue (onSubscribe .maxConcurrentThreads .get () > 1 );
158
+ // ... but the onNext execution should be single threaded
159
+ assertEquals (1 , busyObserver .maxConcurrentThreads .get ());
160
+
161
+ // this should not be the full number of items since the error should stop it before it completes all 9
162
+ System .out .println ("onNext count: " + busyObserver .onNextCount .get ());
163
+ assertFalse (busyObserver .onCompleted );
164
+ assertTrue (busyObserver .onError );
165
+ assertTrue (busyObserver .onNextCount .get () < 9 );
166
+ // no onCompleted because onError was invoked
167
+ // non-deterministic because unsubscribe happens after 'waitToFinish' releases
168
+ // so commenting out for now as this is not a critical thing to test here
169
+ // verify(s, times(1)).unsubscribe();
170
+ }
170
171
}
171
172
172
173
/**
173
174
* A non-realistic use case that tries to expose thread-safety issues by throwing lots of out-of-order
174
175
* events on many threads.
175
- *
176
- * @param w
177
- * @param tw
178
176
*/
179
177
@ Test
180
178
public void runOutOfOrderConcurrencyTest () {
@@ -226,11 +224,6 @@ public void runOutOfOrderConcurrencyTest() {
226
224
}
227
225
}
228
226
229
- /**
230
- *
231
- * @param w
232
- * @param tw
233
- */
234
227
@ Test
235
228
public void runConcurrencyTest () {
236
229
ExecutorService tp = Executors .newFixedThreadPool (20 );
@@ -283,59 +276,68 @@ public void runConcurrencyTest() {
283
276
@ Test
284
277
public void testNotificationDelay () throws InterruptedException {
285
278
ExecutorService tp = Executors .newFixedThreadPool (2 );
279
+ try {
280
+ int n = 10 ;
281
+ for (int i = 0 ; i < n ; i ++) {
282
+ final CountDownLatch firstOnNext = new CountDownLatch (1 );
283
+ final CountDownLatch onNextCount = new CountDownLatch (2 );
284
+ final CountDownLatch latch = new CountDownLatch (1 );
285
+ final CountDownLatch running = new CountDownLatch (2 );
286
286
287
- final CountDownLatch firstOnNext = new CountDownLatch (1 );
288
- final CountDownLatch onNextCount = new CountDownLatch (2 );
289
- final CountDownLatch latch = new CountDownLatch (1 );
287
+ TestSubscriber <String > to = new TestSubscriber <String >(new Observer <String >() {
290
288
291
- TestSubscriber <String > to = new TestSubscriber <String >(new Observer <String >() {
289
+ @ Override
290
+ public void onCompleted () {
292
291
293
- @ Override
294
- public void onCompleted () {
295
-
296
- }
292
+ }
297
293
298
- @ Override
299
- public void onError (Throwable e ) {
294
+ @ Override
295
+ public void onError (Throwable e ) {
300
296
301
- }
297
+ }
302
298
303
- @ Override
304
- public void onNext (String t ) {
305
- firstOnNext .countDown ();
306
- // force it to take time when delivering so the second one is enqueued
307
- try {
308
- latch .await ();
309
- } catch (InterruptedException e ) {
310
- }
311
- }
299
+ @ Override
300
+ public void onNext (String t ) {
301
+ firstOnNext .countDown ();
302
+ // force it to take time when delivering so the second one is enqueued
303
+ try {
304
+ latch .await ();
305
+ } catch (InterruptedException e ) {
306
+ }
307
+ }
312
308
313
- });
314
- Observer <String > o = serializedObserver (to );
309
+ });
310
+ Observer <String > o = serializedObserver (to );
315
311
316
- Future <?> f1 = tp .submit (new OnNextThread (o , 1 , onNextCount ));
317
- Future <?> f2 = tp .submit (new OnNextThread (o , 1 , onNextCount ));
312
+ Future <?> f1 = tp .submit (new OnNextThread (o , 1 , onNextCount , running ));
313
+ Future <?> f2 = tp .submit (new OnNextThread (o , 1 , onNextCount , running ));
318
314
319
- firstOnNext .await ();
315
+ running .await (); // let one of the OnNextThread actually run before proceeding
316
+
317
+ firstOnNext .await ();
320
318
321
- Thread t1 = to .getLastSeenThread ();
322
- System .out .println ("first onNext on thread: " + t1 );
319
+ Thread t1 = to .getLastSeenThread ();
320
+ System .out .println ("first onNext on thread: " + t1 );
323
321
324
- latch .countDown ();
322
+ latch .countDown ();
325
323
326
- waitOnThreads (f1 , f2 );
327
- // not completed yet
324
+ waitOnThreads (f1 , f2 );
325
+ // not completed yet
328
326
329
- assertEquals (2 , to .getOnNextEvents ().size ());
327
+ assertEquals (2 , to .getOnNextEvents ().size ());
330
328
331
- Thread t2 = to .getLastSeenThread ();
332
- System .out .println ("second onNext on thread: " + t2 );
329
+ Thread t2 = to .getLastSeenThread ();
330
+ System .out .println ("second onNext on thread: " + t2 );
333
331
334
- assertSame (t1 , t2 );
332
+ assertSame (t1 , t2 );
335
333
336
- System .out .println (to .getOnNextEvents ());
337
- o .onCompleted ();
338
- System .out .println (to .getOnNextEvents ());
334
+ System .out .println (to .getOnNextEvents ());
335
+ o .onCompleted ();
336
+ System .out .println (to .getOnNextEvents ());
337
+ }
338
+ } finally {
339
+ tp .shutdown ();
340
+ }
339
341
}
340
342
341
343
/**
@@ -435,20 +437,22 @@ public static class OnNextThread implements Runnable {
435
437
private final Observer <String > observer ;
436
438
private final int numStringsToSend ;
437
439
final AtomicInteger produced ;
440
+ private final CountDownLatch running ;
438
441
439
- OnNextThread (Observer <String > observer , int numStringsToSend , CountDownLatch latch ) {
440
- this (observer , numStringsToSend , new AtomicInteger (), latch );
442
+ OnNextThread (Observer <String > observer , int numStringsToSend , CountDownLatch latch , CountDownLatch running ) {
443
+ this (observer , numStringsToSend , new AtomicInteger (), latch , running );
441
444
}
442
445
443
446
OnNextThread (Observer <String > observer , int numStringsToSend , AtomicInteger produced ) {
444
- this (observer , numStringsToSend , produced , null );
447
+ this (observer , numStringsToSend , produced , null , null );
445
448
}
446
449
447
- OnNextThread (Observer <String > observer , int numStringsToSend , AtomicInteger produced , CountDownLatch latch ) {
450
+ OnNextThread (Observer <String > observer , int numStringsToSend , AtomicInteger produced , CountDownLatch latch , CountDownLatch running ) {
448
451
this .observer = observer ;
449
452
this .numStringsToSend = numStringsToSend ;
450
453
this .produced = produced ;
451
454
this .latch = latch ;
455
+ this .running = running ;
452
456
}
453
457
454
458
OnNextThread (Observer <String > observer , int numStringsToSend ) {
@@ -457,6 +461,9 @@ public static class OnNextThread implements Runnable {
457
461
458
462
@ Override
459
463
public void run () {
464
+ if (running != null ) {
465
+ running .countDown ();
466
+ }
460
467
for (int i = 0 ; i < numStringsToSend ; i ++) {
461
468
observer .onNext (Thread .currentThread ().getId () + "-" + i );
462
469
if (latch != null ) {
@@ -603,19 +610,18 @@ public int assertEvents(TestConcurrencyObserverEvent expectedEndingEvent) throws
603
610
/**
604
611
* This spawns a single thread for the subscribe execution
605
612
*/
606
- private static class TestSingleThreadedObservable implements Observable .OnSubscribeFunc <String > {
613
+ private static class TestSingleThreadedObservable implements Observable .OnSubscribe <String > {
607
614
608
- final Subscription s ;
609
615
final String [] values ;
610
616
private Thread t = null ;
611
617
612
- public TestSingleThreadedObservable (final Subscription s , final String ... values ) {
613
- this .s = s ;
618
+ public TestSingleThreadedObservable (final String ... values ) {
614
619
this .values = values ;
615
620
616
621
}
617
622
618
- public Subscription onSubscribe (final Observer <? super String > observer ) {
623
+ @ Override
624
+ public void call (final Subscriber <? super String > observer ) {
619
625
System .out .println ("TestSingleThreadedObservable subscribed to ..." );
620
626
t = new Thread (new Runnable () {
621
627
@@ -637,7 +643,6 @@ public void run() {
637
643
System .out .println ("starting TestSingleThreadedObservable thread" );
638
644
t .start ();
639
645
System .out .println ("done starting TestSingleThreadedObservable thread" );
640
- return s ;
641
646
}
642
647
643
648
public void waitToFinish () {
@@ -653,42 +658,48 @@ public void waitToFinish() {
653
658
/**
654
659
* This spawns a thread for the subscription, then a separate thread for each onNext call.
655
660
*/
656
- private static class TestMultiThreadedObservable implements Observable .OnSubscribeFunc <String > {
661
+ private static class TestMultiThreadedObservable implements Observable .OnSubscribe <String > {
657
662
658
- final Subscription s ;
659
663
final String [] values ;
660
664
Thread t = null ;
661
665
AtomicInteger threadsRunning = new AtomicInteger ();
662
666
AtomicInteger maxConcurrentThreads = new AtomicInteger ();
663
667
ExecutorService threadPool ;
664
668
665
- public TestMultiThreadedObservable (Subscription s , String ... values ) {
666
- this .s = s ;
669
+ public TestMultiThreadedObservable (String ... values ) {
667
670
this .values = values ;
668
671
this .threadPool = Executors .newCachedThreadPool ();
669
672
}
670
673
671
674
@ Override
672
- public Subscription onSubscribe (final Observer <? super String > observer ) {
675
+ public void call (final Subscriber <? super String > observer ) {
673
676
System .out .println ("TestMultiThreadedObservable subscribed to ..." );
674
677
t = new Thread (new Runnable () {
675
678
676
679
@ Override
677
680
public void run () {
678
681
try {
679
682
System .out .println ("running TestMultiThreadedObservable thread" );
683
+ int j = 0 ;
680
684
for (final String s : values ) {
685
+ final int fj = ++j ;
681
686
threadPool .execute (new Runnable () {
682
687
683
688
@ Override
684
689
public void run () {
685
690
threadsRunning .incrementAndGet ();
686
691
try {
687
692
// perform onNext call
688
- System .out .println ("TestMultiThreadedObservable onNext: " + s );
693
+ System .out .println ("TestMultiThreadedObservable onNext: " + s + " on thread " + Thread . currentThread (). getName () );
689
694
if (s == null ) {
690
695
// force an error
691
696
throw new NullPointerException ();
697
+ } else {
698
+ // allow the exception to queue up
699
+ int sleep = (fj % 3 ) * 10 ;
700
+ if (sleep != 0 ) {
701
+ Thread .sleep (sleep );
702
+ }
692
703
}
693
704
observer .onNext (s );
694
705
// capture 'maxThreads'
@@ -714,7 +725,9 @@ public void run() {
714
725
// wait until all threads are done, then mark it as COMPLETED
715
726
try {
716
727
// wait for all the threads to finish
717
- threadPool .awaitTermination (2 , TimeUnit .SECONDS );
728
+ if (!threadPool .awaitTermination (5 , TimeUnit .SECONDS )) {
729
+ System .out .println ("Threadpool did not terminate in time." );
730
+ }
718
731
} catch (InterruptedException e ) {
719
732
throw new RuntimeException (e );
720
733
}
@@ -724,7 +737,6 @@ public void run() {
724
737
System .out .println ("starting TestMultiThreadedObservable thread" );
725
738
t .start ();
726
739
System .out .println ("done starting TestMultiThreadedObservable thread" );
727
- return s ;
728
740
}
729
741
730
742
public void waitToFinish () {
@@ -776,7 +788,7 @@ public void onNext(String args) {
776
788
onNextCount .incrementAndGet ();
777
789
try {
778
790
// simulate doing something computational
779
- Thread .sleep (200 );
791
+ Thread .sleep (100 );
780
792
} catch (InterruptedException e ) {
781
793
e .printStackTrace ();
782
794
}
0 commit comments