TestSubscriber does not receive OnNext when real subscriber would - java

In my test I have the following code:
/* two users written to realm here, verified */
TestSubscriber<RealmResults<User>> testSubscriber = new TestSubscriber<>();
usersByQuery(getRealm().where(User.class))
.filter(RealmResults::isLoaded)
.subscribe(testSubscriber);
/*
.subscribe(users1 -> {
assertTrue("Users are not two, found instead: " + users1.size(), users1.size() == 2);
Log.d("Another test", "" + users1.size() + " users on thread: " + Thread.currentThread().getName());
});
*/
try {
Log.d("Test", "Sleeping on " + Thread.currentThread().getName() + "\n");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
testSubscriber.assertValueCount(1);
The test will fail with:
java.lang.AssertionError: Number of onNext events differ; expected: 1,
actual: 0
If I replace the testSubscriber with the commented subscribe and remove the test subscriber assertion, it will pass and output:
D/Test: Sleeping on mainD/Another test: 2 users on thread: main
I do not understand why the TestSubscribers OnNext will not be called when the other one will. I'd like to use the test subscriber so I can replace the Thread.sleep block with an awaitValueCount.

Related

How to delay asynchronously when a method is called consecutively?

I want to have a delay of 1 minute before the printFirst() method is called without affecting the main thread.
Code
I tried
// define delaying print-method using Timer
static void printFirst() {
new java.util.Timer().schedule(
new java.util.TimerTask() {
public void run() {
System.out.println(ts() + " First");
}
},60000
);
}
// main to run
System.out.println(ts() + " Zero");
printFirst();
printFirst();
printFirst();
System.out.println(ts() + " Second");
System.out.println(ts() + " Third");
System.out.println(ts() + " Fourth");
Actual Output
but the output was
Timestamp: 2023-01-05 17:40:43.664 Zero
Timestamp: 2023-01-05 17:40:43.666 Second
Timestamp: 2023-01-05 17:40:43.667 Third
Timestamp: 2023-01-05 17:40:43.667 Fourth
Timestamp: 2023-01-05 17:41:13.681 First
Timestamp: 2023-01-05 17:41:13.681 First
Timestamp: 2023-01-05 17:41:13.681 First
Expected
I was expecting an interval of 1 min between the 3 lines ending with "First".
Timestamp: 2023-01-05 17:40:43.664 Zero
Timestamp: 2023-01-05 17:40:43.666 Second
Timestamp: 2023-01-05 17:40:43.667 Third
Timestamp: 2023-01-05 17:40:43.667 Fourth
Timestamp: 2023-01-05 17:41:43.667 First
Timestamp: 2023-01-05 17:42:43.667 First
Timestamp: 2023-01-05 17:43:43.667 First
We can achieve the expected results using ExecutorService class with the newSingleThreadExecutor() method. See the code below.
static ExecutorService es = Executors.newSingleThreadExecutor();
static void printFirst() {
es.submit(() -> {
try {
TimeUnit.MILLISECONDS.sleep(60000);
System.out.println(ts() + " First");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
The main method is still the same.
System.out.println(ts() + " Zero");
printFirst();
printFirst();
printFirst();
System.out.println(ts() + " Second");
System.out.println(ts() + " Third");
System.out.println(ts() + " Fourth");
When run, the results are:
2023-01-06 00:05:45.72 Zero
2023-01-06 00:05:45.763 Second
2023-01-06 00:05:45.763 Third
2023-01-06 00:05:45.763 Fourth
2023-01-06 00:06:45.776 First
2023-01-06 00:07:45.782 First
2023-01-06 00:08:45.784 First
As an option you can set up your timer for periodic execution and limit the number of runs
static void printFirst(long delay, int numberOfIterations) {
new java.util.Timer().schedule(
new java.util.TimerTask() {
private int counter = 0;
public void run() {
System.out.println(ts() + " First");
if(++counter == numberOfIterations) {
this.cancel();
}
}
}, delay, delay
);
}
And then just run it with one command printFirst(60000, 3);
Issue
The delay in your Timer.schedule(TimerTask task, long initialDelay) is just for the initial delay, time between scheduled and start of task. See parameter in docs:
delay - delay in milliseconds before task is to be executed.
Solution
For your intent - as interval - you need the overloaded sister-method schedule(TimerTask task, long delay, long period) passing the 1 minute interval as third argument to parameter named period:
Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay. Subsequent executions take place at approximately regular intervals separated by the specified period.
import java.util.Timer;
import java.util.TimerTask;
// define the task, here in a method on demand
public static TimerTask createPrintTask(String text) {
return new TimerTask() {
public void run() {
System.out.println(ts() + text); // not sure how ts() is defined
}
};
}
// define print-method using Timer with interval and zero delay
static void printScheduledWithInterval(String text, int intervalMillis) {
var initialDelayMillis = 0; // start immediately (first after 0 seconds)
new Timer().schedule(createPrintTask(text), initialDelayMillis, intervalMillis);
}
// MAIN
System.out.println(ts() + " Zero");
// use to start the task asynchronously (it will continue to print every interval until canceled)
printScheduledWithInterval(" First", 60_000); // 1 minute interval
System.out.println(ts() + " Second");
System.out.println(ts() + " Third");
System.out.println(ts() + " Fourth");
Note: In you code there was printFirst called 3 times. Presumably to have 3 different tasks started or to have 3 lines printed.
When does the scheduling of task end?
The printScheduledWithInterval here, rather means schedule a print-job to be executed repeatedly on a fixed-interval.
Since there are no requirements about number of printed lines or max-execution count, the timer will continuously start new tasks.
While calling function, you can set the number of seconds as a parameter
System.out.println(ts() + " Zero");
printFirst(60000);
printFirst(12000);
printFirst(18000);
System.out.println(ts() + " Second");
System.out.println(ts() + " Third");
System.out.println(ts() + " Fourth");
In your function,
static void printFirst(long time) {
new java.util.Timer().schedule(
new java.util.TimerTask() {
public void run() {
System.out.println(ts() + " First");
}
},time
);
}

Thread not awake when timed wait elapsed in java

I am study wait(long timeout) in java,and in the offcial document I found below description:
Some other thread invokes the notify method for this object and thread T happens to be arbitrarily chosen as the thread to be awakened.
Some other thread invokes the notifyAll method for this object.
Some other thread interrupts thread T.
The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified.
The last item said The specified amount of real time has elapsed, more or less,so in my option if we invoke wait(time),when time elapsed,the thread should awake itself.
So I wrote below code for test.
public static void testTimedWait() {
Object lock = new Object();
DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");
new Thread(() -> {
synchronized (lock) {
try {
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " start to run");
lock.wait(5_000);
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " finished running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "thread-1").start();
new Thread(() -> {
synchronized (lock) {
try {
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " start to run");
Thread.sleep(10_000);
//lock.notifyAll();
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " finished running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "thread-2").start();
}
In Thread-1 I invoke lock.wait(5_000) and in Thread-2 I invoke Thread.sleep(10_000),so once the code start to run,Thread-1 should awake after 5 seconds and Thread-2 should awake after 10 seconds theoretically.
When we run code above,the result listed like below:
Thread-1 doesn't awake after 5 seconds!
Could someone help to understand why thread not awake when the wait time has elasped,thanks in advance!
Update1:
Change code as below:
public static void testTimedWait() {
Object lock = new Object();
DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");
new Thread(() -> {
synchronized (lock) {
try {
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " start to run");
lock.wait(20_000);
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " finished running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "thread-1").start();
new Thread(() -> {
synchronized (lock) {
try {
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " start to run");
Thread.sleep(10_000);
//lock.notifyAll();
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " finished running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "thread-2").start();
}
Above code make Thread-1 wait for 20 seconds and Thread-2 sleep for 10 seconds,Thread-1 will awake after the specific seconds.Now it works as expected.
Update2:
Remove Thread-2
public static void testTimedWait() {
Object lock = new Object();
DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");
new Thread(() -> {
synchronized (lock) {
try {
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " start to run");
lock.wait(20_000);
System.out.println(LocalTime.now().format(df) + "\t" + Thread.currentThread().getName() + " finished running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "thread-1").start();
}
The test result is also working as expected.But I still do not know why Thread-1 not awake when it wait longer then Thread-2
Your threads are both synchronized on the same object. Therefore, you have to pay attention to the methods’s effect on synchronization:
Object.wait(…):
“This method causes the current thread (referred to here as T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object.”
…
“The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It competes in the usual manner with other threads for the right to synchronize on the object; once it has regained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked.”
Thread.sleep(long): “The thread does not lose ownership of any monitors.”
So, when the first thread invokes wait, it releases the lock, which is the only way how the second thread could even enter the synchronized block. Then, the second thread calls sleep, which does not release the lock. Therefore, after the time has elapsed, the first thread can not proceed, as it can’t acquire the lock, the second thread is still holding.
Of course, if you extend the first thread’s waiting time, to wait longer than the second thread, the lock has been released in the meanwhile and the first thread can proceed immediately after the waiting time.

Parallel stream doesn't look like working in parallel, completely

1. Set's parallelStream doesn't use enough thread.
Java8 parallelStream doesn't working exactly parallel.
In my computer, java8 set's parallelStream is not using enough thread when task's count is smaller than processor's count.
public class ParallelStreamSplitTest {
#Test
public void setStreamParallelTest() {
System.out.printf("Total processor count : %d \n", Runtime.getRuntime().availableProcessors());
long start = System.currentTimeMillis();
IntStream.range(1, 8).boxed().collect(Collectors.toCollection(HashSet::new)).parallelStream().forEach((index) -> {
System.out.println("Starting " + Thread.currentThread().getName() + ", index=" + index + ", " + new Date());
try {
Thread.sleep(1000);
} catch (Exception e) {
}
});
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + "'s elapsed time : " + (end - start));
}
#Test
public void intStreamParallelTest() {
System.out.printf("Total processor count : %d \n", Runtime.getRuntime().availableProcessors());
long start = System.currentTimeMillis();
IntStream.range(1, 8).parallel().forEach(index -> {
System.out.println("Starting " + Thread.currentThread().getName() + ", index=" + index + ", " + new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
});
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + "'s elapsed time : " + (end - start));
}
}
In my code, setStreamParallelTest takes 4 seconds whereas intStreamParallelTest takes 1 second.
I expect that setStreamParallelTest also done in 1 seconds.
Is it bug?
2. Is it okay to use parallel stream to call another api in web application? If it is wrong, why?
My web application need to call another api server in parallel. So I use parallel stream to call api.
Sets.newHashSet(api1, api2, api3, api4).parallelStream().forEach(api -> callApiSync(api))
I think all requests bound for my server share a fork-join pool. so, It looks dangerous when one of api's response is slow.
Is it correct?
The contract for parallelStream says:
Returns a possibly parallel Stream with this collection as its source. It is allowable for this method to return a sequential stream.
If you want to invoke several tasks in parallel, use an ExecutorService.

Rxjava2 blockingSubscribe vs subscribe

I have read the explanation about blockingSubscribe() and subscribe() but neither I can write nor find an example to see the difference of these. It seems that both of these work the same way. Could someone provide an example of these 2, preferably in Java.
blockingSubscribe blocks the current thread and processes the incomnig events on there. You can see this by running some async source:
System.out.println("Before blockingSubscribe");
System.out.println("Before Thread: " + Thread.currentThread());
Observable.interval(1, TimeUnit.SECONDS)
.take(5)
.blockingSubscribe(t -> {
System.out.println("Thread: " + Thread.currentThread());
System.out.println("Value: " + t);
});
System.out.println("After blockingSubscribe");
System.out.println("After Thread: " + Thread.currentThread());
subscribe gives no such confinement and may run on arbitrary threads:
System.out.println("Before subscribe");
System.out.println("Before Thread: " + Thread.currentThread());
Observable.timer(1, TimeUnit.SECONDS, Schedulers.io())
.concatWith(Observable.timer(1, TimeUnit.SECONDS, Schedulers.single()))
.subscribe(t -> {
System.out.println("Thread: " + Thread.currentThread());
System.out.println("Value: " + t);
});
System.out.println("After subscribe");
System.out.println("After Thread: " + Thread.currentThread());
// RxJava uses daemon threads, without this, the app would quit immediately
Thread.sleep(3000);
System.out.println("Done");

Pause execution of a loop in main method till all Threads finish Java 1.5

I am reading multiple arguments from command line using Java 1.5 . The arguments are names of flat files. I loop thru the arguments in the main method and call a method which in turn creates a bunch of threads to process the file. I need to pause the loop till all threads processing the first argument complete and then move on to create threads for the second argument. How can I queue the arguments or pause the loop execution in my main method till all threads processing current argument complete?
Use Threadpools and an Executor. Take a look at the java.util.concurrent package.
for(String argument:args){
//you said you want multiple threads to work on a single argument.
//create callables instead and use a ThreadPool
List<Callable<YourResult>> lstCallables = createCallablesFor(argument);
List<Future<YourResult>> futures = Executors.newCachedThreadPool().invokeAll(lstCallables);
for(Future<YourResult> future:futures){
//this get() waits until the thread behind the current future is done.
// it also returns whatever your callable might return.
future.get();
}
// at this point, all the threads working on the current argument are finished
// and the next loop iteration works on the next argument
}
I wonder if you are looking for something like cyclic barriers.
You need to start the thread job inside the loop for one argument so that after one job is finished next loop is started and next thread job for next argument is started. And further you can work in your thread job where you defined that.
Example: this is just a snippet
for (int i = 0; i < count; i++) {
t[i] = new RunDemo();
String[] serverList = srv[i].split(",");
String logName = filename + "_" + serverList[0] + "_log";
String sql = "INSERT INTO .....(any query)";
t[i].setStr("sqlplus -L " + username[i] + "/" + password[i] + "#"
+ serverList[1] + ":" + serverList[2] + "/" + serverList[3]
+ " #" + filename1);
t[i].setLogName(logName);
t[i].setDirectory(dir);
try{
conn.UpdateQuery(sql);
log.info("Inserted into the table data with query " + sql);
}
catch (Exception e){
log.info("The data can't be inserted into table with " + e.getMessage() + " sql query " + sql);
}
new Thread(t[i]).start();
}
Here in every loop new thread with different serverList is created and started.
Now the job definition is given below:
public void run() {
JShell jshell = new JShell();
try {
log.info("Command is: " + this.str + " log name: " + this.LogName + " in directory: " + this.directory);
jshell.executeCommand(this.str, this.LogName, this.directory);
log.info("Executed command successfully");
} catch (Exception e1) {
log.info("Error at executing command with error stack: ");
e1.printStackTrace();
}
DBConnection conn1 = new DBConnection();
String sql = "UPDATE patcheventlog SET ENDTIME=SYSDATE WHERE LOGFILE='" + this.directory + this.LogName + "'";
try {
//conn1.callConnection("192.168.8.81", "d2he");
conn1.callConnection(ip, sid);
conn1.UpdateQuery(sql);
conn1.disposeConnection();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.print(this.LogName);
}
So this is how you work with the threads inside the loop. You don't need to pause your loop.
Hope that helps.

Categories