我的类中有一个静态列表,内容是从我通过 API 端点获取其内容的文件加载的。除了列表之外,我还保存了列表上次刷新或检查更新时的时间戳。 该列表由类中的方法访问,这些方法是从类外部调用的,但所有方法仅从列表中读取。列表中的书对象也永远不会改变,只能读取。每次调用访问列表的任何方法时,我都会检查时间戳,如果它早于设定的帧,我会检查 API 以了解文件的更改。如果对文件进行了更改,我会启动一个异步线程重新加载文件,一旦完成,我会覆盖列表。
现在这让我对线程安全产生了疑问,因为他们只是在阅读,我认为应该没有问题,而且我还没有发现任何问题。但是大多数访问列表的方法都会对其进行迭代,这让我想知道当方法在迭代列表时保存列表的重新加载时会发生什么。此时它是否已经制作了副本,或者是否正在加载每个索引的每个条目?
我知道,在指定时间范围后使用访问方法的第一个人将获得旧列表,因为迭代将在重新加载之前完成,这很好。
private static List<Book> bookList = new ArrayList<>();
private static long timestamp = 0;
static
{
try
{
bookList = loadBookList();
timestamp = System.currentTimeMillis();
} catch (Exception e)
{
log.error("Failed initial load of bookList : " + e.getMessage());
}
}
public static String getShortFromName(String name) throws UnknownBookException
{
asyncListCheck();
for (Book book: bookList)
{
if (book.getName().equalsIgnoreCase(name))
{
return book.getShort();
}
}
throw new UnknownObjException(MSG_ERR_NOBOOK);
}
[...] More methods that access the list
private static void asyncListCheck()
{
new Thread(() ->
{
try
{
if (isOldList() && fileWasModified())
{
bookList = loadBookList();
timestamp = System.currentTimeMillis();
}
} catch (Exception e)
{
log.error("Failed reload of bookList : " + e.getMessage());
}
}).start();
}
public static List<Book> loadBookList() throws Exception
{
// Make API call
List<Object> objList = // Results end up in here
List<Book> list = new ArrayList<>();
for (Object obj: objList)
{
Map<String, Object> bookMap = (Map<String, Object>) obj;
String name = String.valueOf(bookMap.get("name"));
[...] more of this
Book book = new Book();
[...] set all the fields
list.add(book);
}
return list;
}
使用 Collections.synchronizedList(list) 没有用,因为我只覆盖整个列表。我可以清空列表并重新填充它,但这似乎是不必要的工作?