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
不是 易失性
,所以我不确定它是否会。我最初创建 end()
作为避免易失性的巧妙方法,但现在我不确定它是否真的会达到我的预期。 此外,如果另一个线程调用 hibernate(),哪个线程将进入睡眠状态?我打算让 Foo
睡觉,所以如果这没有达到我的预期,那么非常欢迎其他建议。
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
? Specifically, because active
isn't volatile
, I'm not sure that it will. I initially created end()
as a clever way of avoiding volatile, but now I'm unsure that it will actually do what I intend.
Additionally, if another thread calls hibernate()
, which thread will go to sleep? I'm intending Foo
to sleep, so if this doesn't do what I intend, an alternative suggestion would be very welcome.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不,不会的。或者至少,它不会一直看到它。
如果您希望 run 始终立即看到新值,则分配给变量的线程与读取该变量的线程之间必须存在“紧随其后”的关系。这可以通过以下方式实现:
active
易失性,synchronized
块,AtomicBoolean
,或者java.util.concurrent.*
包。将变量声明为易失性是确保正确同步的一种方法。事实上,正确的同步会带来性能开销。然而,正确的同步对于应用程序的可靠工作至关重要,避免它并不“聪明”。
(如果没有适当的同步,您的程序可能在大多数时间仍然可以工作,甚至可能总是在某些机器上工作。但是,有时它不会工作,实际行为可能取决于您运行该程序的机器,机器负载是什么,以及其他事情。)
发出调用的线程将进入睡眠状态。除非其他线程对同一个 Foo 对象执行
notify
或notifyAll
,否则它不会唤醒。如果您只是想让应用程序进入睡眠状态并稍后唤醒,请使用 Thread.sleep。但请注意,以错误的方式使用
sleep
可能会使您的应用程序缓慢且无响应。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. This can be achieved:active
volatile,synchronized
blocks around the statements that read and write the variable,AtomicBoolean
, orjava.util.concurrent.*
packages.Declaring the variable to be volatile is one way of ensuring proper synchronization. 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.)
The thread that makes the call will go to sleep. And it won't wake up unless some other thread does a
notify
ornotifyAll
on the same Foo object.If you simply want the application to go to sleep and wake up a bit later, use
Thread.sleep
. But beware that usingsleep
in the wrong way can make your application slow and unresponsive.您的怀疑是正确的:因为
active
不是易失性
,因此不能保证run()
会看到另一个线程上所做的更改。一般来说,避免
易失性
的“聪明”方法几乎总是一个坏主意。事实上,即使是volatile
也是您不应该使用的东西。大多数时候,坚持使用锁、监视器或更高级的同步机制会更安全。对于第二个问题,将进入睡眠状态的线程是调用
hibernate()
的线程。该线程将处于休眠状态,直到被中断、遇到虚假唤醒或其他线程调用Foo
notify()/notifyAll()
> 实例的监视器。调用Object#wait()
而不使用检查正在等待的条件的循环包围它通常是错误的。您似乎也对Foo
实例“进入睡眠状态”的想法感到困惑。Foo
实例不是Thread
(甚至不是Runnable
),并且不会创建自己的线程,因此它的想法去睡觉没有多大意义。您可能想要实现的目标是将调用Foo#run()
的线程置于睡眠状态。Your suspicion is correct: because
active
isn'tvolatile
, there is no guarantee thatrun()
will ever see the change made on another thread.Generally speaking, “clever” ways of avoiding
volatile
are almost always a bad idea. In fact, evenvolatile
is something you should prefer not to resort to. 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()
. That thread will sleep until it is interrupted, it experiences a spurious wakeup, or some other thread callsnotify()
/notifyAll()
on theFoo
instance's monitor. It is usually a mistake to callObject#wait()
without surrounding it with a loop that checks the condition being waited for.You also seem to be confused about the idea of aFoo
instance “going to sleep”. AFoo
instance isn't aThread
(or even aRunnable
), and doesn't create its own thread, so the idea of it going to sleep doesn't make a lot of sense. What you are probably trying to achieve is putting the thread callingFoo#run()
to sleep.关于避免 挥发性 的第一个问题,您应该尝试使用线程中断来通知正在运行的线程停止。
使用 interrupt() 实例另一个线程的方法来中断正在运行的线程。
使用 isInterrupted()< /a> 正在运行的线程中的方法来检查中断。
不确定为什么要扩展 Thread 类。如果在这种情况下实现 Runnable,则应该使用 interrupted 在你的运行方法中检查中断。请阅读 javadocs 以了解此方法的一些注意事项。
Regarding your first question of avoiding volatile , you should try using Thread interruption to signal a running thread to stop.
Use interrupt() instance method from another thread to interrupt running thread.
Use isInterrupted() method in your running thread to check for interruption.
Not sure why you want to extend Thread class. If you implements Runnable in that case you should use interrupted in your run method to check for interruption . Please read javadocs to know about some caveats of this method.