簡體   English   中英

內聯初始化的最終成員變量以某種方式為null

[英]Inline-initialized final member variable is somehow null

我在Conversation類中有以下代碼:

private ConversationListener conversationListener = null;
private final Integer conversationListenerLock = 0;

public ConversationListener getConversationListener() {
    synchronized (conversationListenerLock) {
        return conversationListener;
    }
}

我現在有時會遇到以下異常:

java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
    at com.mobileoct.shared.data.Conversation.getConversationListener(Conversation.java:283)
    at com.mobileoct.android.colposcope.main.ConversationManager.loadConversationsForUser(ConversationManager.java:260)
    at com.mobileoct.android.colposcope.main.ConversationManager$1.run(ConversationManager.java:305)
    at android.os.Handler.handleCallback(Handler.java:739)                                    
    at android.os.Handler.dispatchMessage(Handler.java:95)                                    
    at android.os.Looper.loop(Looper.java:148)                                                
    at android.os.HandlerThread.run(HandlerThread.java:61)                                    

似乎不知何故conversationListenerLocknull 怎么可能呢? 如何在不初始化conversationListenerLock值的情況下進入Conversation類的這種公共非靜態方法? 我怎樣才能修復它以免發生這種情況?

(從堆棧跟蹤中可以清楚地看到,這是在Android上運行的,因此看起來是Java的一些不確定版本,非常接近Java 7.something。)


編輯 :回答評論中的一些問題:

我在三星Galaxy J5(SM-J500H)上運行它,運行Android 6.0.1。 (我還沒有在其他設備上運行它,但這是主要的目標設備,所以這並不重要)。

這個類的唯一構造函數是:

public Conversation(String sessionId, String name, String ownerId, String userId) {
    dataType = DATA_TYPE;
    this.setId(UUID.randomUUID().toString());
    this.setSessionId(sessionId);
    this.setName(name);
    this.setOwnerId(ownerId);
    this.setUserId(userId);
}

但是 ,這個類有時會被Gson實例化,如:

Conversation conversation = new GsonBuilder().create().fromJson(jsonString, Conversation.class);

new GsonBuilder().create()之間有更多東西,但我很確定它不相關。)

我不太了解不安全的出版物,知道這是否適合該法案,但它似乎可能是罪魁禍首。


編輯#2 - 這里是“從ctor直接和間接調用的所有代碼,以及所有其他字段的初始化器”(一些從父類復制):

public static final String DATA_TYPE = "conversation";
private static final Class<?> s_postServlet = AddConversation.class;

protected String id;
private String sessionId;
private String name;
private String ownerId; // the user that created the conversation
private Boolean deleted = false;
private Date lastUpdated = new Date();
private User user;
private User owner;
private Session session;
private SortedSet<Collaborator> collaborators = new TreeSet<>();
private SortedSet<Message> messages = new TreeSet<>();
private Set<Notification> notifications = new HashSet<>();
private ConversationListener conversationListener = null;
private final Object conversationListenerLock = new Object();

// From parent class
protected String dataType;
protected Date timestamp = new Date();
protected String userId;


public Conversation(String sessionId, String name, String ownerId, String userId) {
    dataType = DATA_TYPE;
    this.setId(UUID.randomUUID().toString());
    this.setSessionId(sessionId);
    this.setName(name);
    this.setOwnerId(ownerId);
    this.setUserId(userId);
}

public void setId(String id) {
    this.id = id;
}

public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
}

public void setName(String name) {
    this.name = name;
}

public void setOwnerId(String ownerId) {
    this.ownerId = ownerId;
}

// From parent class
public void setUserId(String userId) {
    this.userId = userId;
}

您永遠不應該在Java中的Integer上進行同步。

由於您已將Integer設置為0,因此conversationListenerLock 必須引用其中一個緩存的Integer ,因為它在-128到+127的范圍內。 試圖獲得其顯示器是一個特別糟糕的主意。 該對象不屬於您,僅屬於您的引用

(我建議您的Java平台正在顯示錯誤的診斷,以嘗試處理您提供的問題,我認為這相當於您的JVM中的錯誤。)

因此,根據經驗, 不要嘗試在Java中對Integer進行synchronize :JVM保留對任何 Integer值進行緩存的權限; 不僅僅是我已經陳述過的最小范圍。

最簡單的解決方法是編寫

private final Object conversationListenerLock = new java.lang.Object();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM