简体   繁体   English

Java线程/ volatile

[英]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 ? 如果另一个线程调用end()Foo立即看到active是否为false Specifically, because active isn't volatile , I'm not sure that it will. 具体来说,因为active不易volatile ,我不确定它会不会。 I initially created end() as a clever way of avoiding volatile, but now I'm unsure that it will actually do what I intend. 我最初创建end()作为一种避免volatile的聪明方法,但现在我不确定它实际上会做我想做的事情。 Additionally, if another thread calls hibernate() , which thread will go to sleep? 另外,如果另一个线程调用hibernate() ,哪个线程会进入休眠状态? I'm intending Foo to sleep, so if this doesn't do what I intend, an alternative suggestion would be very welcome. 我打算让Foo睡觉,所以如果这不符合我的意图,那么另一个建议将非常受欢迎。

If another thread calls end(), will Foo immediately see that active is now false? 如果另一个线程调用end(),Foo会立即看到active是否为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. 如果你想让run总是立即看到新值,那么在分配给变量的线程和读取它的线程之间必须存在“后来”关系。 This can be achieved: 这可以实现:

  • by declaring active volatile, 通过宣布active挥发性,
  • by putting synchronized blocks around the statements that read and write the variable, 通过在读取和写入变量的语句周围放置synchronized块,
  • by making the variable an "atomic" type; 通过使变量成为“原子”类型; eg AtomicBoolean , or 例如AtomicBoolean ,或
  • by using some other appropriate concurrency class; 通过使用一些其他适当的并发类; see the java.util.concurrent.* packages. 请参阅java.util.concurrent.*包。

... a clever way of avoiding volatile ... ......一种避免不稳定的聪明方法......

Declaring the variable to be volatile is one way of ensuring proper synchronization. 将变量声明为volatile是确保正确同步的一种方法。 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? 另外,如果另一个线程调用hibernate(),哪个线程会进入休眠状态?

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. 除非某个其他线程在同一个Foo对象上执行notifynotifyAll ,否则它不会被唤醒。

If you simply want the application to go to sleep and wake up a bit later, use Thread.sleep . 如果您只是希望应用程序进入休眠状态并稍后唤醒,请使用Thread.sleep But beware that using sleep in the wrong way can make your application slow and unresponsive. 但请注意,以错误的方式使用sleep会使您的应用程序变得缓慢且无响应。

Your suspicion is correct: because active isn't volatile , there is no guarantee that run() will ever see the change made on another thread. 你的怀疑是正确的:因为active不是volatile ,所以不能保证run()会看到在另一个线程上做出的更改。

Generally speaking, “clever” ways of avoiding volatile are almost always a bad idea. 一般来说,避免volatile “聪明”方法几乎总是一个坏主意。 In fact, even volatile is something you should prefer not to resort to. 事实上,即使是volatile也是你不应该诉诸的东西。 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() . 对于第二个问题,将要进入休眠状态的线程是调用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. 该线程将一直睡眠,直到它被中断,它会经历虚假的唤醒,或者其他一些线程在Foo实例的监视器上调用notify() / notifyAll() It is usually a mistake to call Object#wait() without surrounding it with a loop that checks the condition being waited for. 调用Object#wait()而不用一个检查等待条件的循环来调用它通常是错误的。

You also seem to be confused about the idea of a Foo instance “going to sleep”. 你似乎也对 Foo实例“入睡”的想法感到困惑。 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. Foo实例不是 Thread (甚至是 Runnable ),并且不会创建自己的线程,因此它进入睡眠的想法并没有多大意义。 What you are probably trying to achieve is putting the thread calling Foo#run() to sleep. 您可能尝试实现的是将调用 Foo#run()的线程置于休眠状态。

Regarding your first question of avoiding volatile , you should try using Thread interruption to signal a running thread to stop. 关于避免volatile的第一个问题,您应该尝试使用Thread中断来指示正在运行的线程停止。

Use interrupt() instance method from another thread to interrupt running thread. 使用另一个线程的interrupt()实例方法来中断正在运行的线程。

Use isInterrupted() method in your running thread to check for interruption. 在正在运行的线程中使用isInterrupted()方法来检查中断。

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

Not sure why you want to extend Thread class. 不确定为什么要扩展Thread类。 If you implements Runnable in that case you should use interrupted in your run method to check for interruption . 如果在这种情况下实现Runnable,则应在run方法中使用interrupt来检查中断。 Please read javadocs to know about some caveats of this method. 请阅读javadocs以了解此方法的一些注意事项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM