6

I've been told that using Thread.Sleep() is a bad solution at times that one would want to make some time interval within a loop of actions in a synchronized method.

On the other hand, I have two different threads which are active throughout the running time of my program and also one shared object and when I use Object.wait(long) in that shared object, it causes my GUI to freeze for some time.

what would be a better solution for this problem?


Update This portion of the code is including one of the threads which is starting in GUI:

class temperatureUp extends Thread 
    {
        @Override
        public void run()
        {
        while(true)
        {
            try
            {
                GBC.increaseTemp();
                updateSystemStatus();
            }
            catch(Exception ex)
            {
                StringWriter w = new StringWriter();
                ex.printStackTrace(new PrintWriter(w));
                txtLog.setText(w + "\n" + txtLog.getText());
            }
        }
        }
    };

and this is the synchronized method in shared object, GBC:

public synchronized void increaseTemp() throws InterruptedException{
    // don't increase the temperature if the boiler 
    // is not turned on...
    while (!isBoilerOn) 
        wait(); 

    // increase the current temperature 
    if ((currentTemp + 1) < MAX_TEMP && currentTemp < desiredTemp) {
        Thread.sleep(2000); ///what should put here if not thread sleep?
        currentTemp ++;    
        updateGasBoilerStatus();
    } 
}
Konrad Reiche
  • 27,743
  • 15
  • 106
  • 143
Afflatus
  • 933
  • 1
  • 12
  • 39
  • 1
    You must be causing the [Event Dispatching Thread](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html) to wait. Could you provide a small example in code of how you start your threads and when you call wait()? – theon Jul 28 '12 at 11:33
  • 1
    Take a look at [`SwingWorker`](http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html). Also, see [`this answer`](http://stackoverflow.com/a/11546203/597657) to know how it's working. – Eng.Fouad Jul 28 '12 at 11:34
  • @theon I updated the post and added some portion of the code. – Afflatus Jul 28 '12 at 11:40

5 Answers5

7

Don't sleep inside the synchronized method! Don't wait in GUI event handlers/methods!

Split up the sychronized actions so that the Sleep() call is not called in the GUI thread context.

Maybe use use InvokeLater() for the second bit.

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • I already deactivated the sleep command in GUI. the synchronized method is in another class which as I said it is a shared-object which is being used by two different threads at the same time. – Afflatus Jul 28 '12 at 11:44
4

You could shrink the scope of the synchronize statement. For instance if you are synchronizing on the whole method

public synchronized void foo()

You could remove the modifier and use a synchronized block instead

synchronized (this) {
   // ...
}

and move the Thread.sleep() outside of this block if possible. Only synchronize on those statements which modify states of shared data.

A lot of threading problems regarding Swing are related to the Event Dispatcher Thread and can be easily solved with it. I recommend you read into it.

A little bit background, why you shouldn't call Thread.sleep() inside a synchronization block:

Sleeping or waiting while holding a lock. Calling Thread.sleep with a lock held can prevent other threads from making progress for a long time and is therefore a potentially serious liveness hazard. Calling Object.wait or Condition.await with two locks held poses a similar hazard. [JCIP]

Konrad Reiche
  • 27,743
  • 15
  • 106
  • 143
  • 1
    Thanks, I will read the article on The Event Dispatch Thread and get back to you in case I had another question. – Afflatus Jul 28 '12 at 11:51
  • @Elham In your case I think the whole chapter of *Concurrency in Swing* will help, since the EDT is for updating Swing components and your synchronization problem is about modifying the states of your model. – Konrad Reiche Jul 28 '12 at 11:56
  • actually the updating part works just fine. the problem is I'd like to make it wait after each update so that the user would see the outcome of the process which is done by threads step by step. – Afflatus Jul 28 '12 at 12:51
  • @Elham Where's the snag then? `Thread.sleep` is fine just reduce the synchronization scope to those variables where you modify the state – Konrad Reiche Jul 28 '12 at 13:08
0

I would make use of monitors: http://www.artima.com/insidejvm/ed2/threadsynch4.html Maybe with notify or notifyAll you can solve it. Good luck!

Nuno Aniceto
  • 1,892
  • 1
  • 15
  • 16
  • Thanks, but the thing is the waiting and notifying the thread working just fine in the program. my problem is I want to make it so that the increment presentation in GUI would become slower for the user to see. – Afflatus Jul 28 '12 at 11:43
0

Always keep your Event Dispatcher Thread (EDT) which is responsible for handling your GUI, away from any Non-UI work. Also, don't synchronize the entire method, but synchronize the atomic statements

synchronized(this){
    //...
}
gobernador
  • 5,659
  • 3
  • 32
  • 51
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
  • ok, thanks but how is this going to be an answer to my question?! – Afflatus Jul 29 '12 at 02:10
  • and the only three actions which has been put in my synchronized method are the ones which are necessary to be under same lock in this sequence. I can't shrink the scope any further. – Afflatus Jul 29 '12 at 03:22
-2

You can try this following code :

public static void delay(int waitTime) {
        long endTime = System.currentTimeMillis() + (waitTime * 1000);
        while (System.currentTimeMillis() < endTime) {}
    } 

Call as delay(5). And control will wait for 5 seconds.