0

In the following methods, I have a list to keep the data and I can populate all the data into this menuDTOList. However, when a send a new request after getting all the data from the first request, the menuDTOList still keeps the data of the first request.

As there are 2 methods recursively calls each other, I cannot make the list to be cleared properly. I tried Collections.synchronizedList() for thread-safety, but it does not make any sense. Also tried to clear the list at different steps, but due to recursive method calls, it did not work correctly.

So, how can I clear the list values on each request while keeping them recursive calls between methodA and 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);
        }
    }
}
  • From the code you have shown perhaps `menuDTOList` shouldn't be a field of `Demo`. Instead, create it in `getData` and pass it to `methodA` and `methodB`? – tgdavies Nov 03 '21 at 11:10
  • @tgdavies Thanks a lot for your valuable helps, yes when create my list value to the `getData()` method, it seems to be fixed. **However**, I think when there is concurrent requests, then a new instance is created that is not wanted our singleton approach. So, how can I test this? And how can I fix that problem (maybe I need to use local variables for this list instead of global one). Any idea? –  Nov 03 '21 at 11:37
  • I don't understand the semantics of your class -- are you saying that there can be two concurrent calls to `getData` that you *want* to use the same `menuDTOList` instance? – tgdavies Nov 03 '21 at 11:47
  • yes, something like that. –  Nov 03 '21 at 12:05

2 Answers2

0

Could you please add more details, what is the condition of for loops?

In the current state, I see 2 different problems here.

  1. methodA and methodB are calling each other, seems like the infinite loop problem
  2. Also if you want to make the list just thread-safe for setters, you can create a plain volatile list. Something like volatile List<MenuDTO> menuDTOList = new ArrayList<>() or if you're looking for out of the box data structure, you could use ConcurrentLinkedQueue. Or best of all, provide list as method param and avoid class level variable altogether
Kiran A B
  • 901
  • 1
  • 7
  • 13
  • Thanks a lot for your nice explanations. For **#1**, there is no infinity problem and I retrieve the list properly. So, there is no need to share the loop parameters (I just omitted). For **#2**, could you please post these options in your answer so that I can apply without any mistake? –  Nov 03 '21 at 11:40
  • And also how can I test if concurrent requests affect list value? –  Nov 03 '21 at 11:41
0

If you do:

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

Then each list instance is only used by a single thread, and the list will be available to be garbage collected as soon as the caller of getData discards the reference.

tgdavies
  • 10,307
  • 4
  • 35
  • 40