我在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类的公共非静态方法?
我怎样才能修复它以免发生这种情况?
(从堆栈跟踪中可以清楚地看到,它在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;
}
答案 0 :(得分:2)
您永远不应在Java中使用Integer进行同步。
由于您已将Integer
设置为0,conversationListenerLock
必须引用其中一个缓存的Integer
,因为它是&#39; s在-128到+127的范围内。试图获得其显示器是一个特别糟糕的主意。该对象不属于您,只有引用。
(我建议您的Java平台正在显示错误的诊断,以尝试处理您提供的问题,我认为这相当于您的JVM中的错误。)< / p>
根据经验,不要尝试synchronize
在Java中的Integer
:JVM保留缓存任何内容的权利 Integer
值;不仅仅是我已经陈述过的最小范围。
最简单的解决方法是编写
private final Object conversationListenerLock = new java.lang.Object();