views:

1232

answers:

4

What's the proper way for a Java command line application to do background work without hogging resources? Should it use sleep() in the loop or is there a more elegant/efficient way?

+1  A: 

One place to start is to make sure that only those resources are being used and no other objects (so that they become garbage collected).

Placing sleep() in a single threading application is only going to halt the current thread. If you're trying to accomplish data being processed in the background while information still needs to be presented to the user then it is best to put the background process in a seperate thread.

Ishmael
+3  A: 

I'd only use sleep() if there's no work to be done. For example, if you're doing something like polling a task queue periodically and there's nothing there, sleep for a while then check again, etc.

If you're just trying to make sure you don't hog the CPU but you're still doing real work, you could call Thread.yield() periodically. That will relinquish control of the CPU and let other threads run, but it won't put you to sleep. If other processes don't need the CPU you'll get control back and continue to do your work.

You can also set your thread to a low priority: myThread.setPriority(Thread.MIN_PRIORITY);

As Ishmael said, don't do this in your main thread. Create a "worker thread" instead. That way your UI (GUI or CLI) will still be responsive.

Clayton
It's a nitpick, but I believe that setting the thread priority only sets the priority of the thread within the JVM - it does not set the priority of the OS-level thread. If you're worried about hogging resources outside the JVM, you still need to set the process priority in the OS.
Jared
@Jared: I think you're right about that, and I wouldn't consider it a nitpick. Threading requires OS support and has OS-specific behavior. On an early version of Java for Solaris there was something called Green Threads, which was basically a workaround for a lack of OS threading capability.
Clayton
That's not entirely true. See http://www.javamex.com/tutorials/threads/priority_what.shtml
Peter Štibraný
If you have a task queue, you should use an instance of BlockingQueue<E> which handles wait/notify correctly without resorting to a sleep. When you sleep, you could very well hurt throughput because new tasks are arriving just as you go to sleep.
Dave Ray
@Dave: I agree that blocking is better than sleep() when available. That way you're immediately woken up when the work arrives. The situation I had in mind is the case when "tasks" are received as files in a particular folder. In that case I think you're stuck with sleep().
Clayton
+9  A: 

Some heuristics:

  • Don't attempt to make scheduling decisions in your application. The operating system's scheduler is way better than yours will be. Let it do its job.
  • Don't poll if you don't have to. For instance, instead of sleeping n seconds, then waking up to check a non-blocked socket, block on the socket. This second strategy plays better with the operating system's scheduler.
  • Don't use an enormous heap if you don't have to, and try not to allocate enormous chunks of memory at one time. A thrashing application tends to have a negative effect on system performance.
  • Use buffered I/O. Always. If you think you need non-buffered I/O, be absolutely sure you're right. (You're probably wrong.)
  • Don't spawn a lot of threads. Threads are surprisingly expensive; beyond a certain point, more threads will reduce your application's performance profile. If you have lots of work to do concurrently, learn and use java.util.concurrent.

Of course, this is just a starter list...

Brian Clapper
+2  A: 

There are several ways. I would use ExecutorService... for example:

ExecutorService service = Executors.newCachedThreadPool();

Callable<Result> task = new Callable<Result>() {
    public Result call() throws Exception {
        // code which will be run on background thread
    }
};

Future<Result> future = service.submit(task);

// Next line wait until background task is complete
// without killing CPU. Of course, you can do something
// different here and check your 'future' later.
//
// Note also that future.get() may throw various exceptions too,
// you'll need to handle them properly

Result resultFromBackgroundThread = future.get();

This is Java 5 code, ExecutorService, Callable, Future and similar are in java.util.concurrent package.

Peter Štibraný