我的 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)
看来,不知何故,conversationListenerLock
是null
。怎么可能呢?我如何在没有初始化 conversationListenerLock
值的情况下进入 Conversation 类的这个公共(public)的、非静态 方法?
我该如何解决才能避免这种情况发生?
(从堆栈跟踪可以清楚地看出,这是在 Android 上运行的,因此似乎是某个不确定的 Java 版本,非常接近 Java 7.something。)
编辑:回应评论中的一些问题:
我在运行 Android 6.0.1 的三星 Galaxy J5 (SM-J500H) 上运行此程序。 (我还没有在其他设备上运行它,但这是主要目标设备,所以这无关紧要)。
这个类的唯一构造函数是:
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
设置为 0,conversationListenerLock
必须 引用缓存的 Integer
之一s,因为它在 -128 到 +127 的范围内。试图获得它的显示器是一个特别糟糕的主意。该对象不属于您,仅属于引用。
(我建议您的 Java 平台正在显示诊断错误,以尝试处理您提出的问题,我认为这相当于您的 JVM 中的错误。)
根据经验,不要尝试在 Java 中Integer
上同步
:JVM 保留缓存的权利任何 Integer
值;不仅仅是我已经说明的最小范围。
最简单的解决方法是编写
private final Object conversationListenerLock = new java.lang.Object();
关于java - 内联初始化的最终成员变量不知何故为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44823086/