Implementation of singleton thread-safe list

北战南征 提交于 2020-01-06 15:16:00

问题


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;
    }
}

回答1:


Short answer: no.

public class MyObjectHolder {
  private final List<MyObject> objectList = new List<>();
  public List<MyObject> getObjectList() {          
    return objectList;
  }

This is the preferred singleton pattern.

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);
  }
}

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.

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.

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.




回答2:


No, your code is not thread safe. For example, you could assign objectList in one thread at time X, but set it to null (via clearObjectList()) at time X+1 because you are synchronizing on 2 different objects. The first synchronization is on objectList itself and the second synchronization is on the instance of MyObjectHolder. You should look into locks when using a shared resource instead of using synchonize, specifically something like a ReadWriteLock.



来源:https://stackoverflow.com/questions/20327143/implementation-of-singleton-thread-safe-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!