Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java线程/易失性_Java_Multithreading_Volatile - Fatal编程技术网

Java线程/易失性

Java线程/易失性,java,multithreading,volatile,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()

我有一根线:

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
会立即看到
处于活动状态
现在是
false
?具体来说,因为
活动
不是
易失性
,所以我不确定它是否会。我最初创建了
end()
,作为一种避免volatile的聪明方法,但现在我不确定它是否真的能达到我的目的。
另外,如果另一个线程调用
hibernate()
,哪个线程将进入睡眠状态?我打算睡
Foo
,因此如果这不符合我的意愿,那么另一个建议将是非常受欢迎的。

你的怀疑是正确的:因为
活动的
不是易变的
,所以不能保证
运行()
会在另一个线程上看到所做的更改

一般来说,避免波动的“聪明”方法几乎总是个坏主意。事实上,即使是
volatile
,您也不应该求助于它。大多数情况下,使用锁、监视器或更高级别的同步机制更安全

对于第二个问题,将进入睡眠状态的线程是一个名为
hibernate()
的线程。该线程将一直处于休眠状态,直到被中断、经历虚假唤醒,或在实例的监视器上执行其他一些线程调用
notify()
/
notifyAll()
。调用
对象35; wait()
而不使用循环检查等待的条件通常是错误的

您似乎还对
Foo
实例“进入睡眠”的概念感到困惑。
Foo
实例不是
线程(甚至不是
Runnable
),也不会创建自己的线程,因此它进入睡眠状态的想法没有多大意义。您可能试图实现的是将调用
Foo#run()
的线程置于睡眠状态

如果另一个线程调用end(),Foo会立即看到active现在为false吗

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

如果希望
run
始终立即看到新值,则在分配给变量的线程和读取变量的线程之间必须存在“后面来”关系。这可以通过以下方式实现:

  • 通过声明
    active
    volatile
  • 通过在读写变量的语句周围放置
    synchronized
  • 通过使变量成为“原子”类型;e、 g.
    原子布尔
    ,或
  • 通过使用其他适当的并发类;请参阅
    java.util.concurrent.*
。。。一个避免波动的聪明方法

将变量声明为volatile是确保正确同步的一种方法。事实上,适当的同步会带来性能开销。然而,适当的同步对于应用程序可靠地工作是必不可少的,避免同步并不是“聪明”的

(如果没有适当的同步,您的程序可能大部分时间仍能工作,甚至可能在某些机器上始终能工作。但是,有时它会不工作,实际行为可能取决于您运行程序的机器、机器负载以及其他因素。)

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

发出呼叫的线程将进入睡眠状态。除非其他线程对同一个Foo对象执行
notify
notifyAll
,否则它不会被唤醒


如果您只是想让应用程序进入睡眠状态并稍晚醒来,请使用
Thread.sleep
。但是要注意,以错误的方式使用
sleep
会使应用程序运行缓慢且无响应。

关于避免volatile的第一个问题,您应该尝试使用线程中断来通知正在运行的线程停止

使用另一个线程的实例方法中断正在运行的线程

在运行线程中使用方法检查中断

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

不确定为什么要扩展线程类。如果在这种情况下实现了Runnable,那么应该在run方法中使用来检查中断。请阅读javadocs以了解此方法的一些注意事项

Re:Foo与Foo的一个实例,我知道两者的区别。我只是不想写Foo bar=new Foo();bar.start();问我所有关于酒吧的问题。我不是指
Foo
类和它的一个实例之间的区别;我指的是你的
Foo
类没有扩展
Thread
,因此它本身不是一个线程。。。我意识到有人/不知何故/某个地方没有(大时间)解释说,在几乎所有的硬件上,易失性读取都是便宜的。volatile只是确保了有序语义,volatile read只是一种有序读取,从技术上讲可能会阻止CPU进行某些优化(即无序加载),但您永远不应该在意。易失性写操作成本更高,因为它们需要刷新所有写操作(缓存线),但易失性写操作通常也很少见。