2

我经常看到这样的代码:

Listener mListener;

public void setListener(Listener listener){
   mListener=listener;
}

public void fooFunction(){
   ...
   ...
   if (mListener!=null){
      mListener.notifyFoo();
   }
}

我的问题是:如果在 null 检查和 notifyFoo() 之间另一个线程调用 setListener(null) 怎么办?那可能吗?还是编译器使它成为原子的

4

5 回答 5

5

您可以同步方法

public synchronized void setListener(Listener listener){
   mListener=listener;
}

public synchronized void fooFunction(){
   ...
   ...
   if (mListener!=null){
       mListener.notifyFoo();
   }
}

或者,如果您想要更好的锁粒度

private Object monitor = new Object();

public void setListener(Listener listener){
   synchronized (monitor) {
       mListener=listener;
   }
}

public void fooFunction(){
   ...
   ...
   synchronized (monitor) {
        if (mListener!=null){
           mListener.notifyFoo();
       }
   }
}
于 2013-06-27T09:20:56.963 回答
1

您可以通过使您的块同步来避免这种情况

public synchronized void setListener(Listener listener) {
    ....
}

public synchronized void fooFunction() {
    ....
}
于 2013-06-27T09:19:35.510 回答
1

默认情况下,编译器不会生成任何原子。诚然,听者有可能被设置null在两条线之间。您可以使用synchronized来避免这种情况。

于 2013-06-27T09:20:54.060 回答
0

是的,有可能。将您的 fooFunction 和 setListener 标记为同步,它应该使此代码多线程安全

于 2013-06-27T09:21:09.470 回答
0

同步在这里是多余的。在检查之前复制成员变量null

Listener mListener;

public void setListener(Listener listener){
   mListener=listener;
}

public void fooFunction(){
   ...
   ...
   Listener listener = mListener;
   if (listener!=null){
      listener.notifyFoo();
   }
}
于 2013-06-27T09:35:08.850 回答