I have 2 classes. One (A) collects some data and the other (B) sends the data to TCP/IP clients. The process is asynchronous with refresh rates from nearly zero to a few seconds. Note that this application has no GUI so I won't be able to use many built in "onChange" listeners.
In normal conditions I would simply write the code so that A calls a "send" method on B, passing the data, no problems here.
Now, assume that the rate A collects data is critical (real time) and that A cannot wait for B to complete the sending process (note that B uses TCP, not UDP). The way I implemented this is
If during the send the data is updated a few times it doesn't matter, as long as it doesn't slow down A. Spawning a new thread for each send would in principle not slow down A but it's likely gonna result in a mess.
You can see that B is working in synchronous mode (but A isn't) and it's implemented with a while loop with a Thread.sleep() call. My questions are:
Should I use a timer task instead of the while loop? I know that most people hate the Thread.sleep() call but ultimately the only thing I'm interested is in keeping CPU low.
Isn't there a more elegant way than the synchronous approach? In some cases the data refresh of A is about 1 second and it would be nice if I could just have a listener that would act on an event. In such case a sleep time of 25ms would be a waste of cycles. In other cases it's very fast and I'd like no sleep at all.
*Example: imagine that A is submitting screenshots from your screen and B is sending them to the clients. Only the last one matters and B is gonna go as fast as possible *
Any ideas or suggestions? Please keep things as simple and low cpu as possible
thanks a lot!
I would make it like this:
A collects the data in whatever fashion is appropriate and then post the "next message" to send. If there is already a message pending, let the new message replace / update the previous.
B checks for ay pending messages, if one is available it grabs it and send it to the client(s). However, if no message is pending, then B waits for one to be available.
Object lock = new Object();
Object pending = null;
public void post(Object message) {
synchronized (lock) {
pending = message;
lock.notifyAll();
}
}
public Object getNextMessage() {
Object message;
synchronized (lock) {
while (pending == null) {
try {
lock.wait();
} catch (InterruptedException e) {
// Ignore
}
}
message = pending;
pending = null;
}
return message;
}
Using a queue you could instead do
BlockingDeque<Object> queue = new LinkedBlockingDeque<Object>(1);
public void postMessage(Object message) {
// If previous message is still pending we replace it.
queue.clear();
queue.offer(message);
}
public Object getNextMessage() {
while (true) {
try {
return queue.take();
} catch (InterruptedException e) {
// Ignore interrupts
}
}
}
Of course in both example it would be good to instead of the while (true) use a signal so you can gracefully shut down.
I would set up a LinkedBlockingQueue
between A
and B
whose size should not block A
when the queue becomes full. In A
, the method that collects the data will post it to the queue. In B
, as long as there is an item in the queue, it is new and should be sent out.
If you want B
to take advantage of multiple edits to a message by A
to be merged and sent out as a single update, then I would do it using the Observer
.
A
keeps updating is the Observable
. B
is an observer of this message.A
updates the message, it is an indication for B to take some action.B
can choose to send the update to the clients immediatelyB
can also choose to wait for a certain period of time using a Timer and send the update to clients only after the timer fires off. The code to send update will be the TimerTask.B
would not set the Timer again until A
changes the message.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With