Java线程/易失性

我有一个线程:

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();
        }
    }
 }

如果另一个线程调用end()Foo立即看到active现在是否为false ? 具体来说,因为active不是volatile ,我不确定它会。 我最初创建了end()作为避免易失性的一种聪明方式,但现在我不确定它实际上会按照我的意图做什么。 此外,如果另一个线程调用hibernate() ,哪个线程将进入休眠状态? 我打算让Foo睡觉,所以如果这不符合我的意图,我会非常欢迎其他建议。


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

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

如果您希望立即run以便始终看到新值,则分配给该变量的线程与读取该线程的线程之间必须存在“后续”关系。 这可以实现:

  • 通过宣布active波动,
  • 通过在读取和写入变量的语句周围放置synchronized块,
  • 通过使变量成为“原子”类型; 例如AtomicBoolean
  • 通过使用其他适当的并发类; 请参阅java.util.concurrent.*包。
  • 一种避免挥发的聪明方式

    声明变量是易变的是确保正确同步的一种方法。 事实上,正确的同步会增加性能开销。 但是,适当的同步对于您的应用程序可靠地工作至关重要,并且避免它是不“聪明”的。

    (如果没有正确的同步,你的程序可能大部分时间仍然工作,甚至可能在某些机器上工作,但偶尔也不能工作,实际行为可能取决于你运行程序的机器上,机器负载是什么等等。)

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

    拨打电话的线程将进入睡眠状态。 除非其他线程在相同的Foo对象上执行notifynotifyAll ,否则它不会唤醒。

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


    您的怀疑是正确的:由于active不是volatile ,因此不能保证run()会看到另一个线程所做的更改。

    一般来说,避免volatile “巧妙”方式几乎总是一个坏主意。 事实上,即使是volatile也是你不应该诉诸的。 大多数情况下,坚持使用锁定,监视器或更高级别的同步机制会更安全。

    对于第二个问题,将要进入休眠状态的线程是调用hibernate()的线程。 该线程会一直处于睡眠状态,直到它被中断,虚拟唤醒或其他线程调用Foo实例监视器上的notify() / notifyAll() 。 调用Object#wait()通常是一个错误,没有用一个循环来检查被等待的条件。

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


    关于避免易失性的第一个问题,您应该尝试使用线程中断来指示正在运行的线程停止。

    使用另一个线程的interrupt()实例方法来中断正在运行的线程。

    在运行的线程中使用isInterrupted()方法来检查中断。

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

    不知道为什么要扩展Thread类。 如果在这种情况下实现了Runnable,则应该在运行方法中使用中断来检查中断。 请阅读javadocs以了解关于此方法的一些注意事项。

    链接地址: http://www.djcxy.com/p/91963.html

    上一篇: Java threading/volatile

    下一篇: multimap in .NET