rx java buffer is losing items - java

I have a PublishSubject with this configuration:
PublishSubject<Message> messageObserver =
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
Different threads of my application are writing messages to this PublishSubject via onNext().
As I see, the buffer underlying ObservableBufferTimed.BufferExactBoundedObserver is non thread-safe, because its onNext looks as follows:
public void onNext(T t) {
U b;
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
if (restartTimerOnMaxSize) {
timer.dispose();
}
fastPathOrderedEmit(b, false, this);
try {
b = ObjectHelper.requireNonNull(bufferSupplier.call(), "The buffer supplied is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
dispose();
return;
}
synchronized (this) {
buffer = b;
consumerIndex++;
}
if (restartTimerOnMaxSize) {
timer = w.schedulePeriodically(this, timespan, timespan, unit);
}
}
To make the race condition case more obvious I set the eventsSaveTimeSpanInSeconds and eventsSaveCountparams to 1 (1 event in 1 second).
The problem appears in this block:
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
So, if two messages are buffering at the same time then first message fills the buffer and assigns null to buffer variable. New buffer will be initialized later after the synchronized block. If there is a race condition, when the buffer is null, the second message will not buffered because of the code:
if (b == null) {
return;
}
Is this a defect or a corrrect buffer behavior? How can I avoid this situation?

Use a serialized subject if multiple threads want to call onNext:
Subject<Message> messageObserver = PublishSubject.<Message>create().toSerialized();
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
// from any thread now
messageObserver.onNext(message);

Related

Does LinkedBlockQueue get the lock while calling await?

I found following source code in LinkedBlockingQueue
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
The await method release the lock and after it is signaled, in while loop again, seems it does not have the lock. And in notEmpty<Condition> it specifies that IllegalMonitorStateException would be thrown if not holding the lock during calling await.
This confused me.. Does it hold the lock or not eventually?
of course It holds the lock.to judge whether the data can be token from queue, it uses loop.
when the queue is still empty,it should await again until its notified and the queue count is not zero .

Why task is done when first element in the future list is true?

I'm little confused with tasks in Java multithreading.
Namely, I've 15 objects, which implements Callable and i'm submitting it by ExecutorService. Each Callable has its own progress bar with is updating in for loop with setProgress method.
I want to show 3 of 15 callables which will finish their job in first, second and third position by getting their names and setting it to labels on my scene. Of course each callable has different working time.
I created Task and i'm starting it in new thread and iterating over list of future tasks from my ExecutorService.
The problem is that my labels aren't visible until first element of the future list is true (until first thread is finished). I have really no idea why and i would be very grateful for your help.
public void startButtonClicked() {
Task task = new Task<Void>() {
#Override
public Void call() {
int i = 0;
while (i < 3) {
for (Future<Boolean> future : futures) {
try {
if (future.get() == true && i == 0) {
labelFirst.setVisible(true);
i++;
}
if (future.get() == true && i == 1) {
labelSecond.setVisible(true);
i++;
}
if (future.get() == true && i == 2) {
labelThird.setVisible(true);
i++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
return null;
}
};
for (Callable c : callables) {
futures.add(executorService.submit(c));
}
new Thread(task).start();
executorService.shutdown();
}
In my ideal solution each label will become visible when their callable will finish, so labelSecond should appear some time after labelFirst.
It's my call method in my callable:
public Boolean call() {
double raceTime = ThreadLocalRandom.current().nextDouble(45.0, 60.0);
try {
for (double i = 0; i < raceTime; i += 0.01) {
TimeUnit.MILLISECONDS.sleep(1);
progressBar.setProgress(i / raceTime);
}
} catch (ParseException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
EDIT:
With checking future.isDone() and little changes it works as i wished.
public void startButtonClicked() {
Task task = new Task<Void>() {
#Override
public Void call() {
int i = 0;
while (i < 3) {
i = 0;
for (Future<Boolean> future : futures) {
if (future.isDone() == true) i++;
if (i == 1) {
labelFirst.setVisible(true);
labelFirstCyclistName.setVisible(true);
}
if (i == 2) {
labelSecond.setVisible(true);
labelSecondCyclistName.setVisible(true);
}
if (i == 3) {
labelThird.setVisible(true);
labelThirdCyclistName.setVisible(true);
}
}
}
return null;
}
};
for (Cyclist c : cyclists) {
futures.add(executorService.submit(c));
}
new Thread(task).start();
executorService.shutdown();
}
The problem is that my labels aren't visible until first element of
the future list is true (until first thread is finished). I have
really no idea why and i would be very grateful for your help.
According to the documentation of Future#get
Waits if necessary for the computation to complete, and then retrieves
its result.
Here is your code - pay special attention to a line containing future.get():
public Void call() {
int i = 0;
while (i < 3) {
for (Future<Boolean> future : futures) {
try {
if (future.get() == true && i == 0) {
During the first iteration of the loop the first future is retrieved from futures, and then future.get() stops the execution of the loop and waits (holds) until execution of this first future (the first thread) will finish and will return a result.
Then the loop continues and LabelX..setVisible(true); are called making labels visible.

synchronized block for a while loop's condition

I'm trying to fix a piece of code I've written that currently has race conditions. In doing so I need to put the condition of a while loop in a synchronized block, however I don't want to synchronise the whole while block since that would starve other threads of the resource, which they need. I can't figure a reasonable way of doing it without repetition or breaks in places that slightly obscure the control flow. Below is the gist of the problem code:
while ((numRead = in.read(buffer)) != -1) {
out.write(buffer);
}
and I need to synchronise the use of in. The two potential solutions I could think of (but don't think they're very good) are:
synchronized (this) {
numRead = in.read(buffer);
}
while (numRead != -1) {
out.write(buffer);
synchronized (this) {
numRead = in.read(buffer);
}
}
which has undesirable repetition, and this:
while (true) {
synchronized (this) {
numRead = in.read(buffer);
}
if (numRead == -1)
break;
else
out.write(buffer);
}
which isn't great for readability. Any suggestions?
Try it like below.
public testMyMethod () {
byte[] buffer = new int[1024];
int numRead = -1;
while ((numRead = readInput(buffer)) != -1) {
out.write(buffer);
}
}
//first method
int readInput(byte[] buffer) {
int readLen = -1;
synchronized(in) {
in.read(buffer);
}
return readLen;
}
//second method, more performant about 3 times, just the synchronization parts
private static final ReentrantLock inputLock = new ReentrantLock();
int readInput(byte[] buffer) {
int readLen = -1;
inputLock.lock();
try {
readLen = in.read(buffer);
} finally {
inputLock.unlock();
}
return readLen;
}

Overriding execute method of Executor

I need to override execute method of executor where I need to change the behavior that threads more than core pool size will be created only when queue is full.
However in real time applications this behavior is undesirable as it can lead to unending wait of task present in queue.
I have changed the execute method as below:
public void execute(Runnable command)
{
System.out.println("ActiveCount : " + getActiveCount() + " PoolSize : " + getPoolSize()
+ " QueueSize : " + getQueue().size() +" Idle Threads : " +(getPoolSize()-getActiveCount()));
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
else if (isRunning(c) && workQueue.offer(command))
{
int recheck = ctl.get();
if (getActiveCount() < workerCountOf(recheck) && isRunning(recheck) && workQueue.offer(command)) {
return;
}
if (addWorker(command, false)) {
return;
}
else if (! isRunning(recheck) && remove(command))
{
reject(command);
}
else if (workerCountOf(recheck) == 0)
{
addWorker(null, false);
}
}
else
{
reject(command); // add task to the queue
}
}
Trying to achieve:
CoreThreads -> Non-CoreThreads -> Queue instead of CoreThreads -> Queue -> Non-CoreThreads.
I dont understand why you need to change execute method, I think, max pool size should not be preferred over queue, as I can see in you code.
I had same problem and you can follow the link :
click to follow the thread.
I feel this should be you last choice, try something else first.

Rx Java: Sleep before OnNext (Sleep before emitting from Observable)

Basis a condition in my Observable, I want to delay onNext / onError. My code is as follows:
fun check3(){
val list = arrayListOf(1,2,3,4,5,6,7, null)
val obs = Observable.create<Int> { subscriber ->
list.filter {
it != null
}.map {
if (it!! %2 == 0 ) {
Thread.sleep(3000)
subscriber.onError(IllegalArgumentException("Mod is true"))
} else {
subscriber.onNext(it)
subscriber.onComplete()
}
}
}
}
A sore here being Thread.sleep(3000)
Is there a better way of doing this? Basically I want to delay the onError notification to my subscriber if the if(it %2) condition is met
You can use concatMap to turn the sleep into a non-blocking delay:
Observable.fromIterable(list.filter { it != null })
.concatMap {
if (it!! % 2 == 0) {
return#concatMap Observable.error(IllegalArgumentException("Mod is true"))
.delay(3, TimeUnit.SECONDS, true)
}
Observable.just(it)
}
.take(1)

Categories