【问题标题】:Singleton 被线程访问时返回 null
【发布时间】:2022-01-23 01:54:55
【问题描述】:

正如标题所述,我正在尝试解决一些从 Singleton 读取数据的线程获得空值的问题。我对我们的日志的调查读起来好像是一个并发问题。

Singleton 定义如下:

@Singleton
public class StaticDatabaseEntries {

private static final Map<String,Thing> databaseEntries = new HashMap<>();

@Lock(LockType.READ)
public Thing getThing(String index) {
return databaseEntries.get(index);
}
}

起初我的印象是数据中只有一个元素被破坏,因为对同一项目的访问重复返回 null。对调试条目的进一步访问表明该问题似乎与特定线程隔离。就好像一旦发生任何导致线程上返回 null 的事情都会继续这样做,但仅在受影响的线程上。

此类的早期版本未应用 LockType.READ,因此根据规范假定为 LockType.WRITE。我使用正确的锁部署了更新以启用并发读取。这并没有改善这种情况。

数据在部署时从数据库加载到 HashMap 中,并且在持续时间内保持不变。由于该类未使用@Startup 标记,因此应用程序使用上下文侦听器来触发从数据库加载条目。

由于线程主要执行读取活动,我不认为切换到ConcurrentHashMap 是有益的。我正在考虑删除static final 部分,因为当容器管理并发访问和单例生命周期时,这似乎是不必要的。当容器无法对 EJB 中标记为 final 的事物进行子类化/代理时,我遇到了副作用。

我考虑的另一种可能性是容器软件中存在某种形式的错误。这是在较旧的 Java 1.7 和 JBOSS 6 EAP 上运行的。在最坏的情况下,我将不得不放弃单例模式,而是按需从数据库中加载条目。

【问题讨论】:

  • 您是否最终排除了地图中的条目包含空值的简单可能性,因为它是用空值写入的?
  • 是的。记录来自数据库的初始负载,表明以后显示为 null 的负载确实存在。在一个线程上的条目变为空之前,服务运行正常,因为日志表明特定元素已被访问/使用。

标签: java multithreading concurrency singleton ejb


【解决方案1】:

一般来说:如果您使用线程,读取活动可能会导致问题,如果您正在调用对象方法,那不是线程保存!这正是在大型项目中经常导致无法检测到的错误的原因。

HashMap 不是线程安全的!

你应该切换到ConcurrentHashMap

更多详情,请看这篇文章:https://www.baeldung.com/java-concurrent-map

【讨论】:

  • 这是一个我一直想知道什么是最好的方法的话题。该软件是 Java Enterprise,因此我们倾向于使用容器功能。在这种情况下,它的 @Singleton 注释容器应该保证并发。因此,在这种情况下,基础数据结构也必须像您对ConcurrentHashMap 的建议一样安全吗?考虑到单例的 EJB 规范,这对我来说似乎是多余的。
  • 我还要说,据我所见,并发数据结构主要锁定/在写入活动期间。大多数时候,我们使用@Singleton 在内存中加载和保存配置数据。加载是一次性写入活动,所有其他访问都是读取。在容器管理并发的 EJB 规范之上进行读取活动的趋势是为什么我没有看到我们的项目经常使用写锁定数据结构的原因。我们这样做有错吗?正如所建议的那样,即使阅读也可能是一个问题,那么什么最适合高阅读活动?
  • 在 Bean 托管并发中,容器不控制客户端对 Singleton Session Bean 的同时访问。开发人员需要自己实现并发,请参阅baeldung.com/java-ee-singleton-session-bean 对于我的理解,这意味着StaticDatabaseEntries 被容器正确地管理为单例,但对象内部的方法必须自己实现并发。如果我错了,请纠正我。
  • 据我了解,容器默认应用/假定应该管理 EJB 的并发性,除非另有指定使用 bean 管理的并发性。然后,除非另有说明,否则它还会为所有函数应用/假定 LockType.WRITE。这就是为什么我们的代码没有实现任何锁定的原因,也是为什么我认为使用ConcurrentHashMap 是多余的。在 EJB 中使用并发数据结构(其并发由容器管理)会创建两层锁定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多