Java - Thread.sleep in the main method

13,502

Solution 1

You're really arguing about design decisions, not performance decisions.

Your colleague's statement about how Thread.sleep is implemented is basically incorrect as far as I can see. On a sensible JVM on a sensible operating system, Thread.sleep() is implemented using an O/S native method for parking a thread (or putting it in a "timed wait" state or whatever you want to call it on your OS). Or put another way, while a thread is sleeping, it consumes zero CPU. And in any case, TimerTask will use Thread.sleep (or similar-- I don't just recall if it uses the park() method introduced in Java 5, but it essentially makes no difference).

The JVM won't generally make secret under-the-hood decisions about threading. If you ask for another thread, you'll get one; if you don't, you won't. A few "housekeeping" threads will be created for garbage collection etc, but as far as your code is concerned, you can assume that no secret clever thread creation is going on.

So, coming back to your questions:

  • sleeping in the main thread is perfectly safe per se; obviously, while the main thread is sleeping, it won't be executing anything, but if you don't need it to, then that's fine;
  • whether you use Thread.sleep() directly in your code or use one of the "timer" utility methods is again a design decision based on whether you want to use a general library that removes implementational details from your code, or whether you prefer to have those details present and under your control; performance-wise, it will make little odds if you implement things correctly;
  • whether you have a static method or have an instance of Collector doesn't essentially matter-- it's just a design decision that you need to make based on what seems more intuitive: do you see Collector as a "general utility" class, or as a "thing" with state that you request to perform operations?

Solution 2

You're confusing sleep and wait. sleep makes the current thread idle for some period of time, and then the thread restarts on its own. wait is a method of Object. It's used to put a thread in a waiting state, and it will only go out of this state if another thread wakes him up using notify or notifyAll on the same object. Using wait if there's only one thread executing will just make your program hang eternally.

Read http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

Solution 3

I think your colleague doesn't really understand the JVM and its threading model; your code is not going to magically multi-thread unless you explicitly make it that way. Further, I think both of you are working too hard at this. Give the Quartz library a try: http://quartz-scheduler.org/documentation/quartz-2.1.x/quick-start

My reasoning is that Java Threading is difficult to get right, especially when you find yourself doing wait/notify on your own, and grappling with all of the edge cases. The quartz library has abstracted this all away and put the repetitive aspect behind the familiar CRON pattern.

I would totally avoid TimerTask as it has the nasty habit of silently failing if there are any unhandled exceptions that occur during your run.

Calling static methods or not is no big deal regardless of your solution, the key is understanding what state gets shared across threads and either eliminate the sharing OR synchronize the access to it so all Threads get a consistent view of the data. If I was in your position, I would give Quartz a shot. If you are reluctant to add yet another library, JDK 1.5 (I think) brought in the ScheduledExectutorService which I think does repetitive tasks.

No matter which way you go, don't write the scheduling/exectution framework yourself. This is a solved problem in Quartz or the ScheduledExectutorService.

Share:
13,502
Bostone
Author by

Bostone

Most of my past experience is in Enterprise Java and related technologies. I started working with Java in 1996, prior to that I did about 5 years of C/C++ My last 8 years are all contract jobs for large clients, all loosely related to Spring framework and other various Open Source frameworks. Since 2008 I've been closely involved with Android development, authoring and writing Jobrio (a.k.a. Hire-A-Droid) and Droidin. I'm also collaborating with good folks of Flud reader to deliver Android version of their popular app I also (occasionally) maintain my dev blog

Updated on June 09, 2022

Comments

  • Bostone
    Bostone over 1 year

    I'm reviewing Java code that essentially is a recurring process that moves/reads/parses some files on regular basis and outputs data into the database. The repeating part is done (roughly) as follows:

    public class CollectorMain {
        public static boolean signalRecieved = false;
        public static void main(String[] args) {
             Runtime.getRuntime().addShutdownHook(new Thread() {
                  public void run() {  
                  shutdown(); 
             }});
             while(!signalRecieved) {
                  Collector.execute();
                  try {
                      Thread.sleep(60 * 1000);
                  } catch (InterruptedException e) {
                      break;
                  }
             }
             // some shutdown logic
        }
        public static void shutdown() {
            signalReceived = true;
        }
    }
    
    public class Collector() {
        public static void execute() {
            // Move files from the queue dir to temp location
            // Read, parse files and insert records into database. 
            // Then delete the processed files
        }
    }
    

    My recommendation was to refactor code to

    1. Create instance of Collector and refactor static execute() method to the instance method
    2. To use Runnable or TimerTask to handle invocations

    My argument was that using Thread.wait from the main method and combining it with static access is not a good way of handling repeatable process especially doing file IO. To which the author replied (quoting)

    The description of Runnable says "should be implemented by any class whose instances are intended to be executed by a thread". In fact, I am intentionally avoiding threads in this program, for reasons of cost vrs.performance requirements.

    Here's another quote from same discussion which will hopefully help to clarify the author's position

    Technically, Java isn't executed at all, it is interpreted by the JVM which then executes machine instructions, to simulate that the Java code is executing. So it's really the JVM that is executing on a thread, or multiple threads.

    But as a Java code writer, I don't care. If I don't create "threads" in Java, then It's the job of the JVM to appear as if there are no threads — even if the JVM is using threads "under the covers".

    A Java Pause is not executed, it is simulated by a sequence of machine instructions that may or may not call an OS 'wait'. (It probably does, because the JVM would not want to spin, burning CPU cycles, but that's a JVM implementation choice).

    So I have 2 questions:

    1. Is putting Thread.wait into the main method legit, safe and advisable way of doing repeatable task in this instance? And if not, why not since there's only one (main) thread of execution?
    2. What are the pitfals of using static metods in this context (if any)?

    I'll be happy to provide additional info if you have any other questions.

  • ziesemer
    ziesemer almost 12 years
    @JBNizet - Fixed. You're correct, wait is declared on Object, but technically, Thread has it as well through inheritance from Object. :-)
  • ziesemer
    ziesemer almost 12 years
    Using the overridden wait method that accepts a timeout can be used as an alternative to sleep, allowing it to return by either a call to notify(All), or once the timeout elapses.
  • JB Nizet
    JB Nizet almost 12 years
    This design makes the shutdown run in parallel to the collector. The original code makes sure that the shutdown is done in the same thread as the collector, which is probably important (if, for example, the shutdown consists in closing a socket or a connection that the collector is using). To me, if several threads are not needed, the original solution is OK.
  • Bostone
    Bostone almost 12 years
    Quartz was on my list of recommend solutions
  • Bostone
    Bostone almost 12 years
    I like this answer. I'll wait for discussion to continue a bit but for now yours is my favorite answer
  • JB Nizet
    JB Nizet almost 12 years
    Anyway it seems to me that the shutdown hook doesn't serve any purpose, since it doesn do the shutdown itself, but only asks the main thread to do it by changing a boolean variable. The JVM will halt as soon as the last shutdown hook thread has finished. It could thus halt before or in the middle of the shutdown logic. If the shutdown hook is not useful, there is just one thread left, and waiting makes no sense in this case.
  • Bob Kuhar
    Bob Kuhar almost 12 years
    Runnable in Java is an abstraction of a task to be executed on a Thread. Every program that runs in Java does so on a Thread, be it the Main Thread or some other Thread. The challenge the DroidIn.net guy gave us how best to handle a recurring task in his system. This had me thinking of Runnable and its relationship to Threads. Threading isn't necessary, but this problem is accounted for pretty well with the JDK's Threading mechanisms, their extensions like ScheduledExectutorService, or a library like Quartz. Don't write this code yourself.