Java线程/ volatile

And*_*man 5 java multithreading volatile

我有一个帖子:

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();
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

如果另一个线程调用end(),会Foo立即看到active现在是false什么?具体来说,因为active不是volatile,我不确定它会不会.我最初创建的end()是一种避免易变的聪明方法,但现在我不确定它实际上会做我想做的事情.另外,如果另一个线程调用hibernate(),哪个线程将进入休眠状态?我打算Foo睡觉,所以如果这不符合我的意图,那么另一个建议将非常受欢迎.

Ste*_*n C 12

如果另一个线程调用end(),Foo会立即看到active是否为false?

不,不会.或者至少,它不会一直看到它.

如果要run始终立即看到新值,则分配给变量的线程与读取它的线程之间必须存在"后来"关系.这可以实现:

  • 通过宣布active挥发性,
  • 通过在synchronized读取和写入变量的语句周围放置块,
  • 通过使变量成为"原子"类型; 例如AtomicBoolean,或
  • 通过使用一些其他适当的并发类; 看到java.util.concurrent.*包裹.

......一种避免不稳定的聪明方法......

将变量声明为volatile是确保正确同步的一种方法.事实上,正确的同步会带来性能开销.但是,正确的同步对于您的应用程序可靠地工作至关重要,并且避免它并不"聪明".

(如果没有适当的同步,你的程序可能仍然可以在大多数时间工作,它甚至可能总是在某些机器上工作.但是,偶尔它将无法工作,实际行为可能取决于你运行程序的机器在什么,机器负载是什么,以及其他东西.)

另外,如果另一个线程调用hibernate(),哪个线程会进入休眠状态?

进行调用的线程将进入休眠状态.除非其它线程做了也不会醒来notifynotifyAll同一Foo对象上.

如果您只是希望应用程序进入睡眠状态并稍后唤醒,请使用Thread.sleep.但请注意,sleep以错误的方式使用会使您的应用程序变得缓慢且无响应.


Stu*_*ook 5

你的怀疑是正确的:因为active不是volatile,所以不能保证run()会在另一个线程上看到更改.

一般来说,"聪明"的避免volatile方式几乎总是一个坏主意.事实上,甚至volatile是你不应该诉诸的东西.大多数情况下,坚持使用锁,监视器或更高级别的同步机制更安全.

对于你的第二个问题,将要进入睡眠的线程就是那个调用的线程hibernate().该线程将休眠,直到它被中断,它经历了一个虚假唤醒,或者其他某个线程调用notify()/ notifyAll()Foo实例的监视器.如果Object#wait()没有用一个检查等待条件的循环来调用它通常是一个错误.

您似乎也对Foo实例"入睡" 的想法感到困惑.一个Foo实例不是Thread(或者甚至是一个Runnable),并且没有创建自己的线程,所以它进入睡眠的想法并没有多大意义.你可能想要实现的是让线程调用Foo#run()睡眠.