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.
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:
active
volatile,synchronized
blocks around the statements that read and write the variable, AtomicBoolean
, orjava.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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With