开发者

Java threading/volatile

开发者 https://www.devze.com 2023-03-31 16:43 出处:网络
I have a thread: class Foo extends Thread { boolean active = true; public void run() { while(active) { //do stuff

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开发者_Go百科 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:

  • 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.


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.


Regarding your first question of avoiding volatile , you should try using Thread interruption to signal a running thread to stop.

Use interrupt() instance method from another thread to interrupt running thread.

Use isInterrupted() method in your running thread to check for interruption.

while(!this.isInterrupted()){
   //do your work here.
}

Not sure why you want to extend Thread class. If you implements Runnable in that case you should use interrupted in your run method to check for interruption . Please read javadocs to know about some caveats of this method.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号