繁体   English   中英

单例线程安全列表的实现

[英]Implementation of singleton thread-safe list

我正在使用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将接收到该列表为空的信息,但是一秒钟后它包含大量数据。 您需要通过重复轮询或使用观察者模式来通知其他线程来处理这种情况。

不,您的代码不是线程安全的。 例如,您可以在X objectList在一个线程中分配objectList ,但是在X + 1时刻将其设置为null(通过clearObjectList() ),因为您要在2个不同的对象上进行同步。 第一次同步在objectList本身上,第二次同步在MyObjectHolder实例上。 使用共享资源而不是使用synchonize ,应该仔细研究锁,尤其是类似ReadWriteLock之类的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM