Java 单例线程安全列表的实现

Java 单例线程安全列表的实现,java,multithreading,spring,concurrency,singleton,Java,Multithreading,Spring,Concurrency,Singleton,我使用的是Spring框架。需要有一个对象列表,该列表应该一次从数据库获取所有数据。当数据更改时,列表将为null,下一个get操作应该再次填充数据库中的数据。我的代码适用于多线程环境吗 @Component @Scope("singleton") public class MyObjectHolder { private volatile List<MyObject> objectList = null; public List<MyObject> g

我使用的是Spring框架。需要有一个对象列表,该列表应该一次从数据库获取所有数据。当数据更改时,列表将为null,下一个get操作应该再次填充数据库中的数据。我的代码适用于多线程环境吗

@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;
    }
}
@组件
@范围(“单例”)
公共类MyObjectHolder{
私有易失性列表objectList=null;
公共列表getObjectList(){
if(objectList==null){
已同步(对象列表){
if(objectList==null){
objectList=getFromDB();
}
}
}
返回对象列表;
}
同步的
公共无效clearObjectList(){
objectList=null;
}
}
简短回答:否

public class MyObjectHolder {
  private final List<MyObject> objectList = new List<>();
  public List<MyObject> getObjectList() {          
    return objectList;
  }
公共类MyObjectHolder{
私有最终列表objectList=新列表();
公共列表getObjectList(){
返回对象列表;
}
这是首选的单例模式

现在,您需要弄清楚如何以线程安全的方式将数据放入列表中。因为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);
  }
}
公共类MyObjectHolder{
private final CopyOnWriteArrayList objectList=新建CopyOnWriteArrayList();
公共列表getObjectList(){
返回对象列表;
}
公共布尔值isEmtpy(){
返回objectList.isEmpty();
}
public void readDB(){
最终列表dbList=getFromDB();
//??objectList.clear();
addAll(dbList);
}
}
请注意,没有任何同步,但它是完全线程安全的。Java保证该列表上的调用以原子方式执行。因此,我可以调用
isEmpty()
当其他人正在填写列表时。我只能得到一个瞬间的快照,无法判断我会得到什么结果,但在所有情况下都会成功,不会出错

DB调用首先写入一个临时列表中,因此此处不会出现线程问题。然后,
addAll()
将自动将内容移动到真正的列表中,同样:所有线程安全

最坏的情况是线程A即将写入新数据,而线程B同时检查列表是否包含任何元素。线程B将收到列表为空的信息,但一微秒后它包含大量数据。您需要通过重复轮询或使用通知其他线程的观察者模式。

简短回答:否

public class MyObjectHolder {
  private final List<MyObject> objectList = new List<>();
  public List<MyObject> getObjectList() {          
    return objectList;
  }
公共类MyObjectHolder{
私有最终列表objectList=新列表();
公共列表getObjectList(){
返回对象列表;
}
这是首选的单例模式

现在,您需要弄清楚如何以线程安全的方式将数据放入列表中。因为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);
  }
}
公共类MyObjectHolder{
private final CopyOnWriteArrayList objectList=新建CopyOnWriteArrayList();
公共列表getObjectList(){
返回对象列表;
}
公共布尔值isEmtpy(){
返回objectList.isEmpty();
}
public void readDB(){
最终列表dbList=getFromDB();
//??objectList.clear();
addAll(dbList);
}
}
请注意,没有任何同步,但它是完全线程安全的。Java保证该列表上的调用以原子方式执行。因此,我可以调用
isEmpty()
当其他人正在填写列表时。我只能得到一个瞬间的快照,无法判断我会得到什么结果,但在所有情况下都会成功,不会出错

DB调用首先写入一个临时列表中,因此此处不会出现线程问题。然后,
addAll()
将自动将内容移动到真正的列表中,同样:所有线程安全


最坏的情况是线程A即将写入新数据,而线程B同时检查列表是否包含任何元素。线程B将收到列表为空的信息,但一微秒后它包含大量数据。您需要通过重复轮询或使用用于通知其他线程的观察者模式。

否,您的代码不是线程安全的。例如,您可以在时间X在一个线程中分配
objectList
,但将其设置为null(通过
clearObjectList()
)在时间X+1时,因为您正在两个不同的对象上进行同步。第一次同步在
objectList
本身上,第二次同步在
MyObjectHolder
实例上。在使用共享资源时,您应该查看锁,而不是使用
synchonize
,特别是类似于>不,您的代码不是线程安全的。例如,您可以在时间X在一个线程中分配
objectList
,但将其设置为null(通过
clearObjectList()
)在时间X+1时,因为您正在两个不同的对象上进行同步。第一次同步在
objectList
本身上,第二次同步在
MyObjectHolder
的实例上。在使用共享资源时,您应该查看锁,而不是使用
synchonize
,特别是类似于需要getObjectList()检查列表是否为空,如果为空则填充。这应该是一个原子操作。其他线程可以随时从列表中删除项目。当您说“其他线程可以随时从列表中删除项目”时,您是指其他线程可以清除列表还是删除spe