TimerTasks in Swing

GlobalDictator
GlobalDictator used Ask the Experts™
on
Hi,

I'm trying to write a message acknowledgement application where I need to:
a) Add every new message on a message queue. Just using an Arraylist for creating a message queue.
b) Notify a timertask to expect an acknowledge in 50 sec for the message so make it to either sleep for 50sec or wake up when an acknowledgement is received.

What is the best practice to implement this?

Thanks
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Use two thread pools.
1. arrivedMsgs
2. acknowledgedMsgs.

final ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10); // up to 10 msgs could be queued
ThreadPoolExecutor arrivedPool = new ThreadPoolExecutor(2, 2, 10, TimeUnit.SECONDS, queue);
when msg arrives do:

arrivedPool.execute(new ArrivedMsg());

class ArrivedMsg implements Runnable {
 public void run() {
  // process the message, when the message is processed create new Msg and send it to
  // acknowledgedMsgs pool to be processed
  acknowledgedMsgs.execute(new AcknowledgedMsg());
 }
}

class AcknowledgedMsg implements Runnable {
   public void run() {
   // here process the Acknowledgment
   }
}

Author

Commented:
@ Valeri,

Thanks for this. But I was just wondering wheather it was possible to use Swing.Timer or util.Timer class to achieve the same. Could you please provide the code using them

Thanks
Top Expert 2016

Commented:
>>b) Notify a timertask to expect an acknowledge in 50 sec for the message so make it to either sleep for 50sec or wake up when an acknowledgement is received.

Wake up from what? A messaging application sends and/or receives messages. What will it do when it receives the message?
Amazon Web Services

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

Author

Commented:
@CEHJ

Basically we have a timeout of 50 secs for receiving an acknowledgement to confirm successfull delivery of any message. So, we could receive an acknowledgement at any stage upto 50 sec. Hence i just wanted a timer task that sleeps for 50 secs and wakes up just before 50 secs or when an acknowledgement is received. But If we dont receive an acknowledgement back within 50 secs, we update the status of that msg as failure.

Also, there could be multiple msgs that were being sent. Hence when we receive an acknowledgment, it needs to be checked which msg is it for before updating the status of that particular msg as successful.

I hope that makes sense.. The part to design the TimerTask and how to make it to wake up before its sleep time is completed, upon an event ie when a message comes in, is what I need help with.

Thanks
Top Expert 2016

Commented:
You should probably just have a thread that runs continuously processing a queue of message status objects
ok, I got the point...
Assume that your messages are identified by unique ID of type long.
So create your own "message queue" to keep messages arrived in this way:
public class MsgQueue {
    private TreeMap<Long, YourMsg> msgs = new TreeMap<Long, YourMsg>();

    public synchronized YourMsg addMsg(YourMsg msg) {
        return msgs.put(msg.getId(), msg);
    }

    public synchronized YourMsg removeMsg(YourMsg msg) {
        return msgs.remove(msg.getId());
    }

    public synchronized void removeOld(long time) {
        YourMsg msg;
        for ( long key : msgs.keySet() ) {
            msg = msgs.get( key );
            if (msg.getTime() + 50000 < time) msgs.remove(key);
        }
    }
}
In this way you will keep all of the msgs arrived and still with unknown staus.
If acknowledge msg comes, you can identify it in your queue by ID, and to remove it by calling removeMsg. If the difference between time of the msg in the queue and time of the acknowledge msg is > 50000 ms, then mark it as failed, otherwise mark it as succesfull.
So in this way you will have in your queue only msgs  with unknown status.
Now from time to time you have to remove msgs that have stayed in the queue more than 50000 ms and to mark them as failed.
You can do this in this way:

import java.util.TimerTask;

public final class CheckMsgs extends TimerTask {
  public void run(){
    msgQueue.removeOld(System.currentTimeMillis()); // means: remove msgs stayed in teh queue more than 50000 ms
  }
}

TimerTask checkMsgs  = new CheckMsgs();
Timer timer = new Timer();
timer.scheduleAtFixedRate(checkMsgs, 0, 1000); // check every second

I think that its the best solution for you
YourMsg is something like that

public class YourMsg {
    private long id;
    private long time;

    public YourMsg() {
        this.time = System.currentTimeMillis();
    }

    public long getId() { return id; }
    public long getTime() { return time; }
}

Author

Commented:
@Valeri:

Thanks very much for this. I'll give it a go and let you know if it works or in case there are any issues.

Cheers
Solution that timer wakes up for every arrived msg after 50 sec is also option, but I think it will be more expensive, because I suppose that most of the msgs will be sucessfull...

Author

Commented:
Yes that correct. The acknowledement usually would be coming sonner than the lifetime of 50 sec after a msg   has been sent. Hence, I need some mechanism which would either make the thread to wake up as soon as an ack arrives or on 50 sec and check for the ack.
Yes, you are right! So you can make a little changes to the proposed algoritm.
Instead of removing all msgs from the queue, that have stayed in the queue more than 50 sec, you can do this:
1. Start Timer, it's better to be daemon timer.
2. When msg arrives, create class like that:
public final class NewMsgArrived extends TimerTask {
  long id;
  public void run() {
       // this code will be executed after 50000 ms, because it is sceduled for this in Timer.
       // check if the msg it this id is in the queue, if it is not in teh queue, it means that in a meantime acknowledge has arrived and the msg is already marked as successful, othervise msg is in the queue and it should be marked as failed.
  }
}

timer.schedule(new NewMsgArrived(), 50000);
 now remove your code that checks every second:
public final class CheckMsgs extends TimerTask {
  public void run(){
    msgQueue.removeOld(System.currentTimeMillis()); // means: remove msgs stayed in teh queue more than 50000 ms
  }
}

TimerTask checkMsgs  = new CheckMsgs();
timer.scheduleAtFixedRate(checkMsgs, 0, 1000); // check every second

some changes to the above text:

// check if the msg WITH this id is in the queue, if it is not in teh queue, it means that in a meantime acknowledge has arrived and the msg is already marked as successful, othervise msg is in the queue and it should be marked as failed /because it is expired already/ AND IT SHOULD BE REMOVED FROM THE QUEUE!
This will prevent checking every second for expired msgs, stayed more than 50 sec in the queue, and it's the fastest solution according to me.

Author

Commented:
Excellent solution

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial