实现单例线程安全列表 [英] Implementation of singleton thread-safe list

查看:122
本文介绍了实现单例线程安全列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using Spring framework. Need to have a list of objects, which should get all data from database at once. When data is changed, list will be null and next get operation should fill data from database again. Is my code correct for multi-thread environment?

@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已经在并发包中有一些预先建立的线程安全列表,这应该优先于任何同步实现,因为它们在繁重的线程下速度更快。

Now you need to figure out how to get the data into the list in a thread-safe way. For this Java already has some pre-made thread-safe lists in the concurrent package, which should be preferred to any synchronized implementation, as they are much faster under heavy threading.

您的问题可以这样解决:

Your problem could be solved like this:

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(),而有人正在填写列表。我只能得到一个时间的快照,不能告诉我会得到什么结果,但在任何情况下都会成功而不会出错。

Please note the absence of any synchronized, yet the thing is completely thread-safe. Java guarantees that the calls on that list are performed atomically. So I can call isEmpty() while someone else is filling up the list. I will only get a snapshot of a moment in time and can't tell what result I will get, but it will in all cases succeed without error.

DB调用首先写入临时列表,因此在这里不会发生线程问题。然后 addAll()将原子地将内容移动到真实列表中,再次:所有线程安全。

The DB call is first written into a temporary list, therefore no threading issues can happen here. Then the addAll() will atomically move the content into the real list, again: all thread-safe.

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

The worst-case scenario is that Thread A is just about done writing the new data, while at the same time Thread B checks if the list contains any elements. Thread B will receive the information that the list is empty, yet a microsecond later it contains tons of data. You need to deal with this situation by either repeatedly polling or by using an observer pattern to notify the other threads.

这篇关于实现单例线程安全列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆