我正在使用Spring框架。需要有一个对象列表,它应该立即从数据库中获取所有数据。当数据更改时,列表将为空,下一次获取操作应再次从数据库填充数据。我的代码对于多线程环境正确吗?
@Component
@Scope("singleton")
public class MyObjectHolder {
private volatile List<MyObject> objectList = null;
public List<MyObject> getObjectList() {
if (objectList == null) {
synchronized (objectList) {
if (objectList == null) {
objectList = getFromDB();
}
}
}
return objectList;
}
synchronized
public void clearObjectList() {
objectList = null;
}
}
最佳答案
简短回答:不。
public class MyObjectHolder {
private final List<MyObject> objectList = new List<>();
public List<MyObject> getObjectList() {
return objectList;
}
这是首选的单例模式。
现在您需要弄清楚如何以线程安全的方式将数据放入列表中。为此,Java 已经在并发包中提供了一些预制的线程安全列表,这应该优于任何同步实现,因为它们在重线程下要快得多。
您的问题可以这样解决:
public class MyObjectHolder {
private final CopyOnWriteArrayList<MyObject> objectList = new CopyOnWriteArrayList<>();
public List<MyObject> getObjectList() {
return objectList;
}
public boolean isEmtpy() {
return objectList.isEmpty();
}
public void readDB() {
final List<MyObject> dbList = getFromDB();
// ?? objectList.clear();
objectList.addAll(dbList);
}
}
请注意,没有任何同步,但它是完全线程安全的。 Java 保证该列表上的调用以原子方式执行。所以我可以在其他人填写列表时调用 isEmpty()
。我只会得到某个时刻的快照,无法知道会得到什么结果,但在所有情况下都会成功而不会出现错误。
数据库调用首先写入临时列表,因此这里不会发生线程问题。然后,addAll()
会自动将内容移动到实际列表中,同样:都是线程安全的。
最坏的情况是线程 A 即将完成新数据的写入,同时线程 B 检查列表是否包含任何元素。线程 B 将收到列表为空的信息,但一微秒后它包含大量数据。您需要通过重复轮询或使用观察者模式通知其他线程来处理这种情况。
关于java - 单例线程安全列表的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20327143/