Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java threading/volatile

I have a thread:

class Foo extends Thread
{
    boolean active = true;

    public void run()
    {
        while(active)
        {
            //do stuff
        }
    }

    public void end()
    {
        active = false;
    }

    public void hibernate()
    {
        synchronized(this)
        {
            wait();
        }
    }
 }

If another thread calls end(), will Foo immediately see that active is now false? Specifically, because active isn't volatile, I'm not sure that it will. I initially created end() as a clever way of avoiding volatile, but now I'm unsure that it will actually do what I intend. Additionally, if another thread calls hibernate(), which thread will go to sleep? I'm intending Foo to sleep, so if this doesn't do what I intend, an alternative suggestion would be very welcome.

like image 312
Andy Shulman Avatar asked Aug 27 '11 02:08

Andy Shulman


Video Answer


2 Answers

If another thread calls end(), will Foo immediately see that active is now false?

No it won't. Or at least, it won't see it all of the time.

If you want run to always see the new value immediately, there has to be a "comes after" relationship between the thread assigning to the variable and the thread reading it. This can be achieved:

  • by declaring active volatile,
  • by putting synchronized blocks around the statements that read and write the variable,
  • by making the variable an "atomic" type; e.g. AtomicBoolean, or
  • by using some other appropriate concurrency class; see the java.util.concurrent.* packages.

... a clever way of avoiding volatile ...

Declaring the variable to be volatile is one way of ensuring proper synchronization. It is a fact that proper synchronization imposes a performance overhead. However, proper synchronization is essential for your application to work reliably, and it is NOT "clever" to avoid it.

(Without proper synchronization, your program will probably still work most of the time, and it might even always work on some machines. However, occasionally it won't work, and the actual behavior is likely to depend on what machine you run the program on, what the machine load is, and other things.)

Additionally, if another thread calls hibernate(), which thread will go to sleep?

The thread that makes the call will go to sleep. And it won't wake up unless some other thread does a notify or notifyAll on the same Foo object.

If you simply want the application to go to sleep and wake up a bit later, use Thread.sleep. But beware that using sleep in the wrong way can make your application slow and unresponsive.

like image 118
Stephen C Avatar answered Sep 23 '22 18:09

Stephen C


Your suspicion is correct: because active isn't volatile, there is no guarantee that run() will ever see the change made on another thread.

Generally speaking, “clever” ways of avoiding volatile are almost always a bad idea. In fact, even volatile is something you should prefer not to resort to. Most of the time it's safer to stick to locks, monitors, or higher-level synchronization mechanisms.

For your second question, the thread that will go to sleep is the one that called hibernate(). That thread will sleep until it is interrupted, it experiences a spurious wakeup, or some other thread calls notify()/notifyAll() on the Foo instance's monitor. It is usually a mistake to call Object#wait() without surrounding it with a loop that checks the condition being waited for.

You also seem to be confused about the idea of a Foo instance “going to sleep”. A Foo instance isn't a Thread (or even a Runnable), and doesn't create its own thread, so the idea of it going to sleep doesn't make a lot of sense. What you are probably trying to achieve is putting the thread calling Foo#run() to sleep.

like image 20
Stuart Cook Avatar answered Sep 26 '22 18:09

Stuart Cook