[英]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.