using sleep() for a single thread
Asked Answered
R

4

5

I am fairly new to java, and am starting to get into using different threads in order to use wait() or sleep() on one part of my code and have the others still run.

For this project, I am using JFrame with the javax.swing.* and java.awt.* imports. What I am trying to do is have one of the threads (in my code it is the main, starting thread) allow the player to choose a space on the tic tac toe board, and when they click it, it will change icons, and then the AI will wait for 1 second before playing back from the second thread that I created.

Unfortunately, whenever I call ait.sleep(1000) (ait is my thread name) both threads wait for 1 second before finishing their execution. Can anyone tell me why sleeping one thread is stopping my whole execution?

Reprehension answered 28/12, 2012 at 18:55 Comment(2)
Are you calling ait.sleep(1000) from inside the ait thread or from some other thread?Each
yes, i am calling sleep(1000) from inside aitReprehension
B
15

Can anyone tell me why sleeping one thread is stopping my whole execution

to better explain your Swing GUI is created on its own special thread separate from that which main() and other code will run in, this is done via creating your Swing components in the SwingUtilities.invokeXXX block (even if you have not done this your GUI will be run on a single thread called the initial thread) . Now if you simply call sleep while on Event Dispatch Thread (or for that matter on the same Thread) it will wait for the call to Thread.sleep to finish. Now because all Swing events are processed on EDT we pause its execution by calling sleep(..) thus pausing the UI events from being processed and therefore GUI is frozen (until sleep(..) returns).

You should not use Thread.sleep(..) on Event Dispatch Thread (or any Thread where sleep will cuase unwanted execution blocking), as this will cause the UI to seem frozen.

Here is a nice example which demonstrates exactly, this unwanted behavior caused by invoking Thread.sleep(..) on GUI's EDT.

Rather use:

  • Swing Timer for example:

    int delay=1000;// wait for second
    
    Timer timer = new Timer(delay, new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            //action that you want performed 
        }
    });
    //timer.setRepeats(false);//the timer should only go off once
    timer.start();
    
  • Swing Worker

or if no Swing components are being created/modified:

  • TimerTask

  • Thread, you would then use Thread.sleep(int milis) (but thats last option in any case IMO)

UPDATE

Swing Timer/SwingWorker was only added in Java 1.6, however, TimerTask and Thread have been around for alot longer sine Java 1.3 and JDK 1 repsectively, thus you could even use either of the 2 above methods and wrap calls that create/manipulate Swing components in SwingUtilities/EventQueue#invokeXX block; thats the way things used to be done :P

Binucleate answered 28/12, 2012 at 19:4 Comment(1)
thank you so much, Swing Timer worked perfectly and my program is running with far less clutter. thanks againReprehension
P
3

Thread.sleep is a static method. Invocations of it via the reference of any given Thread is simply a form of convenience.

As a result, any invocation of sleep is really calling sleep on the current Thread, which I suspect is the Event Thread in your case. Sleeping/blocking on the Event Thread will give the appearance of being locked up.

Platinous answered 28/12, 2012 at 19:28 Comment(0)
E
2

If you want the ait thread to sleep, then code that thread to sleep. Designs where one thread "reaches into" another and pushes it around at a low level are fundamentally broken. You write the code for every thread, so write it to do what you want it to do in the first place so you'll find no need to reach into it from the outside.

Which makes more sense, for the person in the kitchen to know how to cook breakfast or the person in the bedroom to yell down and direct them to perform each step of making breakfast? Sure, you might tell them to make breakfast. But you definitely don't direct each step at a low level.

Each answered 28/12, 2012 at 19:4 Comment(0)
U
1

Thread.sleep is a static method which causes the currently executing thread to sleep for the specified amount of time. Java syntax allows you to call a static method via a variable, but the compiler simply uses the compile-time type of that variable to determine which method to call, i.e.

Thread ait = null;
ait.sleep(1000); // calls Thread.sleep(1000), causing current thread to sleep.
                 // In particular, does *not* NPE

You also mentioned wait() - while this is an instance method rather than a static it still causes the current thread to do the waiting (ait.wait(1000) would cause the current thread to wait for up to 1 second or until another thread calls ait.notifyAll()).

There is a Thread.suspend() and its counterpart resume() that were introduced in the very early days of Java to allow one thread to control another, but they were deprecated soon after as they are inherently deadlock-prone. The recommended pattern if you want one thread to "control" another is to do it co-operatively, i.e. have some kind of shared flag that thread A sets and thread B reads, and have B send itself to sleep according to the flag:

volatile boolean threadBShouldRun = true;

// Thread B
while(true) {
  if(threadBShouldRun) {
    // do some stuff
  } else {
    Thread.sleep(1000);
  }
}

// Thread A
if(someCondition) {
  threadBShouldRun = false;
}

but it's generally easier and less error-prone to make use of the facilities that exist in the java.util.concurrent package. Doing multi-threading right is much harder than it appears on the surface.

Urus answered 28/12, 2012 at 19:29 Comment(2)
instead of volatile why not AtomicBoolean?Binucleate
@DavidKroukamp that would be another option yes, though for booleans where one thread is only setting and another is only getting it doesn't really buy you anything over a plain volatile. It's different if you actually need the atomic getAndSet or compareAndSet operations of course.Urus

© 2022 - 2024 — McMap. All rights reserved.