为什么 Java 即使使用并发列表也会为每个请求保留列表值?
Why Java keeps List values for each request even using concurrent list?
在下面的方法中,我有一个列表来保存数据,我可以将所有数据填充到这个 menuDTOList
中。但是,当从第一个请求获取所有数据后发送新请求时,menuDTOList
仍然保留第一个请求的数据。
由于有2个方法相互递归调用,我无法正确清除列表。我用 Collections.synchronizedList()
换 thread-safety
,但没有任何意义。也尝试过在不同的步骤中清除列表,但由于递归方法调用,它没有正常工作。
那么,如何清除每个请求的列表值,同时保持它们在 methodA
和 methodB
之间进行递归调用?
public class Demo {
// private List<MenuDTO> menuDTOList = new ArrayList<>();
List<MenuDTO> menuDTOList =
Collections.synchronizedList(new ArrayList<MenuDTO>());
protected Iterable<MenuDTO> getData() {
for (...) {
methodA();
}
return menuDTOList;
}
private void methodA(final MenuItemExpandedDTO menuItemExpandedDTO) {
menuDTOList.add(dto);
for (...) {
methodB();
}
}
private void methodB() {
for (...) {
methodA(dto);
}
}
}
能否请您补充更多细节,for
循环的条件是什么?
在当前状态下,我在这里看到 2 个不同的问题。
- methodA和methodB互相调用,好像是死循环问题
- 此外,如果您想让列表对于设置器来说只是线程安全的,您可以创建一个普通的易变列表。类似
volatile List<MenuDTO> menuDTOList = new ArrayList<>()
的东西,或者如果您正在寻找开箱即用的数据结构,您可以使用 ConcurrentLinkedQueue
。或者最重要的是,提供列表作为方法参数并完全避免 class 级别变量
如果你这样做:
public class Demo {
protected Iterable<MenuDTO> getData() {
List<MenuDTO> menuDTOList = new ArrayList<>();
for (...) {
methodA(menuDTOList);
}
return menuDTOList;
}
private void methodA(final MenuItemExpandedDTO menuItemExpandedDTO, final List<MenuDTO> menuDTOList) {
menuDTOList.add(dto);
for (...) {
methodB(menuDTOList);
}
}
private void methodB(List<MenuDTO> menuDTOList) {
for (...) {
methodA(dto, menuDTOList);
}
}
}
然后每个列表实例仅由单个线程使用,一旦 getData
的调用者丢弃引用,列表将可用于垃圾收集。
在下面的方法中,我有一个列表来保存数据,我可以将所有数据填充到这个 menuDTOList
中。但是,当从第一个请求获取所有数据后发送新请求时,menuDTOList
仍然保留第一个请求的数据。
由于有2个方法相互递归调用,我无法正确清除列表。我用 Collections.synchronizedList()
换 thread-safety
,但没有任何意义。也尝试过在不同的步骤中清除列表,但由于递归方法调用,它没有正常工作。
那么,如何清除每个请求的列表值,同时保持它们在 methodA
和 methodB
之间进行递归调用?
public class Demo {
// private List<MenuDTO> menuDTOList = new ArrayList<>();
List<MenuDTO> menuDTOList =
Collections.synchronizedList(new ArrayList<MenuDTO>());
protected Iterable<MenuDTO> getData() {
for (...) {
methodA();
}
return menuDTOList;
}
private void methodA(final MenuItemExpandedDTO menuItemExpandedDTO) {
menuDTOList.add(dto);
for (...) {
methodB();
}
}
private void methodB() {
for (...) {
methodA(dto);
}
}
}
能否请您补充更多细节,for
循环的条件是什么?
在当前状态下,我在这里看到 2 个不同的问题。
- methodA和methodB互相调用,好像是死循环问题
- 此外,如果您想让列表对于设置器来说只是线程安全的,您可以创建一个普通的易变列表。类似
volatile List<MenuDTO> menuDTOList = new ArrayList<>()
的东西,或者如果您正在寻找开箱即用的数据结构,您可以使用ConcurrentLinkedQueue
。或者最重要的是,提供列表作为方法参数并完全避免 class 级别变量
如果你这样做:
public class Demo {
protected Iterable<MenuDTO> getData() {
List<MenuDTO> menuDTOList = new ArrayList<>();
for (...) {
methodA(menuDTOList);
}
return menuDTOList;
}
private void methodA(final MenuItemExpandedDTO menuItemExpandedDTO, final List<MenuDTO> menuDTOList) {
menuDTOList.add(dto);
for (...) {
methodB(menuDTOList);
}
}
private void methodB(List<MenuDTO> menuDTOList) {
for (...) {
methodA(dto, menuDTOList);
}
}
}
然后每个列表实例仅由单个线程使用,一旦 getData
的调用者丢弃引用,列表将可用于垃圾收集。