[英]java - do I have to declare my shared listener member variable as volatile?
我有一个简单的类,它在自己的线程中进行一些计算,并将结果报告给监听器。
class Calculator extends Thread {
protected Listener listener;
public void setListener(Listener l) {
listener = l;
}
public void run() {
while (running) {
... do something ...
Listener l = listener;
if (l != null) {
l.onEvent(...);
}
}
}
}
在任何时候,如果用户在一段时间内不想要任何事件,则可以调用setListener(null) 。 因此,在run()函数中,我创建了一个侦听器的副本,因此我不能遇到NullPointerException ,如果在!= null条件检查成功后将侦听器设置为null,则可能会发生这种情况。 就我而言,我相信这是同步它的正确选择。
我的问题是:我应该在这里声明监听器成员变量为volatile吗? 我已经阅读了很多关于volatile的内容,但是所有的例子似乎都是针对基本数据类型(boolean,int,...),而不是Objects。 因此,我不确定对象是否应该/可以被声明为volatile。 我相信我必须声明它是volatile,所以线程总是有成员变量的最新版本,但我不确定。
谢谢!
是。 为了保证Calculator
线程看到一个新值,由另一个线程设置,你必须使变量volatile。
但是, volatile
是一种非常低级别的机制,很少用于客户端代码。 我建议你考虑在这个场景中使用java.util.concurrent.AtomicReference
,这可以确保这些东西按预期工作。
如果使用此方法,则无法保证在setListener(null)
返回后侦听器不会收到事件通知。 执行可以如下进行:
Listener l = listener; // listener != null at this point
// setListener(null) executes here
if (l != null) {
l.onEvent(...);
}
如果需要保证在取消注册后没有事件发布到侦听器,则需要使用synchronized块。 声明listener
器是volatile
也无济于事。 代码应该是:
public synchronized void setListener(Listener l) {
listener = l;
}
public void run() {
while (running) {
... do something ...
synchronized (this) {
if (listener != null) {
listener.onEvent(...);
}
}
}
}
如果您想一直避免synchronized
费用,可以这样做:
if (listener != null) {
synchronized (this) {
if (listener != null) {
listener.onEvent(...);
}
}
}
这会产生一个轻微的风险,即在设置非空侦听器后您将错过一个事件。 声明listener
器是volatile
可能会解决这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.