我有一个帖子:
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
,哪个线程将进入休眠状态?我打算{{1}}睡觉,所以如果这不符合我的意图,那么另一个建议将非常受欢迎。
答案 0 :(得分:12)
如果另一个线程调用end(),Foo会立即看到active是否为false?
不,不会。或者至少,它不会一直看到它。
如果希望run
始终立即看到新值,则在分配给变量的线程和读取它的线程之间必须存在“后来”关系。这可以实现:
active
volatile,synchronized
块,AtomicBoolean
或java.util.concurrent.*
包。......一种避免不稳定的聪明方法......
将变量声明为volatile是确保正确同步的一种方法。事实上,正确的同步会带来性能开销。但是,正确的同步对于您的应用程序可靠地工作至关重要,并且避免它并不“聪明”。
(如果没有正确的同步,你的程序可能仍然可以在大多数情况下工作,它甚至可能总是在某些机器上工作。但是,偶尔它不会工作,实际的行为很可能取决于你的机器运行程序,机器负载是什么,以及其他什么。)
另外,如果另一个线程调用hibernate(),哪个线程会进入休眠状态?
进行通话的线程将进入休眠状态。除非某个其他线程在同一个Foo对象上执行notify
或notifyAll
,否则它不会被唤醒。
如果您只是希望应用程序进入睡眠模式并稍后唤醒,请使用Thread.sleep
。但请注意,以错误的方式使用sleep
会使您的应用程序变得缓慢且无响应。
答案 1 :(得分:5)
您的怀疑是正确的:因为active
不是volatile
,所以无法保证run()
能够看到在另一个主题上进行的更改。
一般来说,避免volatile
的“聪明”方式几乎总是一个坏主意。事实上,即使volatile
也是你不应该诉诸的东西。大多数情况下,坚持使用锁,监视器或更高级别的同步机制更安全。
对于第二个问题,将要进入睡眠状态的线程是调用hibernate()
的线程。该线程将一直睡眠,直到它被中断,它会在notify()
实例的监视器上遇到虚假唤醒或其他线程调用notifyAll()
/ Foo
。调用Object#wait()
而不用一个检查等待条件的循环来调用它是错误的。
你似乎也对 Foo
实例“睡觉”的想法感到困惑。 Foo
实例不是Thread
(甚至是Runnable
),并且不创建自己的线程,因此它进入睡眠状态的想法不会很多感觉。您可能尝试实现的是将调用Foo#run()
的线程置于休眠状态。
答案 2 :(得分:0)
关于避免volatile的第一个问题,你应该尝试使用Thread中断来指示正在运行的线程停止。
使用另一个线程中的interrupt()实例方法来中断正在运行的线程。
在正在运行的线程中使用isInterrupted()方法检查中断。
while(!this.isInterrupted()){
//do your work here.
}
不确定为什么要扩展Thread类。如果在这种情况下实现Runnable,则应在run方法中使用interrupted来检查中断。请阅读javadocs以了解此方法的一些注意事项。