tags:

views:

121

answers:

3

I need to write some code to stress-test RS232 communication using rxtx (note: this question is NOT about serial communications, so please don't go there), and I would like to periodically send bytes using some kind of timer task.

Are there any kind of guidelines online about what kind of timer class to use for various applications? I'm not sure whether I should use javax.swing.Timer or java.util.Timer or java.util.concurrent.ScheduledExecutorService or something else.

Also at what frequency do they start to break down? I would guess that it's along the lines of the operating system timeslice (forget what it is in Windows, 1msec-10msec seems about what I remember). I want to run at the fastest frequency that will not give me problems on my PC; I can always spit out more bytes out my serial port at a time, I'd just like to do it in as much of a periodic fashion as I can.

+1  A: 

If you want a high frequency yet accurate frequency, I wouldn't use a timer.

I did something much like this once in Delphi, providing quick pulses to a stepper motor. I was at liberty to chew up as much CPU time as I wanted for this, so I ran a tight loop that checked Windows' high precision timer until the right amount of time had passed, and then did the action I needed.

It's not quite as convenient in Java, but I'd recommend a similar approach, using System.nanoTime().

You may find you missed the last time mark. If so, deal with it somehow. Either hurry and do your action anyway, or do whatever needs doing to compensate for the error - maybe wait for an entire character space to pass, or whatever. Also, you may want to modify the time interval to the next event. Whatever it takes to accurately deal with the normal jitter, in other words.

If you don't do a lot of object creation in your loop, there's no sensible reason why your garbage collector should kick in, so your timing has a reasonable chance of remaining accurate.


Update

Jonathan Feinberg admonishes me that ScheduledExecutorService is made for this kind of thing. I contend that it's not suitable for the high-frequency, high precision requirement of the OP.

I have a link here from someone complaining in a Sun forum about accuracy problems using this technique: His repeat rate is only 200 ms and yet he's experiencing delays of over 1 second!

Problem with the Java way of doing this is that it's using the operating system's facilities for doing this in a mostly cross-platform manner, and in a way that won't negatively impact the rest of the system. These are compromises; when you have a priority on getting a lot of events out fast and accurately, and you have some leeway on the constraints, it is possible to construct a solution that works better. This is exactly what I've outlined.

Carl Smotricz
Given that Java is at the mercy of the OS--per the resource you link to--your suggestion of using System.nanoTime() and doing event scheduling by hand will do no better on the affected platforms.
Jonathan Feinberg
I don't have a high-frequency or high-precision requirement, just would like to do things as well as possible w/o having to work too hard. I've done the hard real-time stuff before: in QNX (RTOS) on a PXA270 and it had jitter on the order of several hundred microseconds worst-case for scheduling tasks, good enough for most things... but for rock-solid timing you really need a processor with a high-priority interrupt that you have lots of control over. (but +1 for bringing up good points)
Jason S
@Jason: Thanks for the +1 :) Hope it works out well for you. @Jonathan: By relinquishing control far less often than the "standard" solution, mine is far less often a victim of the OS. I have no problem with you being unwilling to understand this, though.
Carl Smotricz
oh, stop bickering you two :-) there's always going to be portability vs. performance tradeoffs. spin-wait solutions rule when you can waste CPU cycles.
Jason S
+1  A: 

Don't use the Swing timer; that's a kluge from early Swing days.

The ScheduledExecutorService is the more general and configurable of the two remaining contenders. It accepts nanosecond precision, but of course cannot provide any better than milisecond accuracy depending on platform. You'd need a real-time JVM for nanosecond accuracy.

Jonathan Feinberg
A: 

Why not just create your own Thread?

public MyThread extends Thread {
    int frequency = 10; // number per second
    AtomicBoolean shutDown = new AtomicBoolean();

    public void run() {
        while (!shutDown.get()) {
            long startTime = System.nanoTime() / 1000000;
            try {
                performAction();
            } catch (Exception e) {
                System.err.println(e.toString());
            }
            long elapsedTime = startTime - System.nanoTime() / 1000000;

            long sleepTime = 1000 / frequency - elapsedTime;
            if (sleepTime > 0) {
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    // ignored
                }
            }
        }
    }
}

If you must increase the resolution of a timer on the Windows system you can use the Thread.sleep(Long.MAX_VALUE) technique.

Pool
I'd rather use ScheduledExecutorService as it provides some more functionality (dealing with things like interruptions etc.), also just because you call Thread.sleep() with a constant value doesn't mean your tasks will execute periodically as it depends on how long the task takes to run.
Jason S
Updated to take those into account - if only for academic reasons.
Pool
See http://www.ibm.com/developerworks/java/library/j-jtp05236.html on how to properly handle InterruptedException (you should not ignore it).
Steve Kuo
Thanks Steve, but that's outside the scope of the question.
Pool
not really -- cancellation is fairly common; and I want to make sure I avoid concurrency or other problems.
Jason S
So handle interrupt as appropriate.... There's lots of good reasons to use timers over Threads, but I don't see them in this case.
Pool