Почему Spring Boot @ Asyn c отбрасывает элементы в моем аргументе List? - PullRequest
0 голосов
/ 10 февраля 2020

У меня возникла проблема с потоком в аннотации метода @Async, где один аргумент содержит перечисление List и отбрасывает элементы. Список очень маленький, 2 предмета. Отбрасывание предметов происходит не сразу, но иногда для его появления требуются часы или дни.

Это общий поток нашей программы:

A Controller создает Сказал List в своем методе @RequestMapping, передает список классу Service, который выполняет вызов базы данных для пакетной обработки и запускает событие для каждого элемента из базы данных, передавая список. Этот список в конечном итоге передается в метод @Async, который затем отбрасывает либо первый элемент, либо оба элемента.

Controller.methodA() 
  -> Creates list with two items in it
  -> Calls void Service.methodX(list) 
    -> Load batch from database
    -> Iterate over batch
      -> Print items from list --- list in tact
      -> Calls void AsyncService.asyncMethod(list)
        -> Print items from list --- eventually drops items here always the first item, sometimes both.

Конфигурация кода и образец «голых костей»:

Мы настроили его на 2 потока:

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setMaxPoolSize(5);  // Never actually creates 5 threads
        threadPoolTaskExecutor.setCorePoolSize(2); // Only 2 threads are ever created
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}

Это локальная реплика, которая пытается вызвать проблему с ядром, но не повезло:

@RestController
public class ThreadingController {

    private final ThreadingService threadingService;

    public ThreadingController(ThreadingService threadingService) {
        this.threadingService = threadingService;
    }

    @GetMapping("/test")
    public void testThreads() {
        List<SomeEnum> list = new ArrayList<>();
        list.add(SomeEnum.FIRST_ENUM);
        list.add(SomeEnum.SECOND_ENUM);

        for (int i = 0; i < 1000; i++) {
            this.threadingService.workSomeThreads(i, list);
        }
    }
}
public enum SomeEnum {
    FIRST_ENUM("FIRST_ENUM"),
    SECOND_ENUM("SECOND_ENUM");

    @Getter
    private String name;

    SomeEnum(String name) {
        this.name = name;
    }

}
@Slf4j
@Service
public class ThreadingService {

    @Async
    public void workSomeThreads(int i, List<SomeEnum> list) {
        try {
            Thread.sleep(100L);  // Add some delay to slow things down to trigger GC or other tests during processing
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("Count {} ; Here are the list items: {}", i, list.toString());
        assert(list.size() == 2);
    }
}

Если мы посмотрим на это, у меня будет один контроллер, имитирующий как Controller, так и Service, упомянутые ранее. Он вращается через пакет данных, отправляя один и тот же список снова и снова. В другом классе есть метод ayn c, чтобы проверить, что список такой же. Я не смог воспроизвести проблему локально, но это основная проблема.

Насколько мне известно, Java является передачей по ссылке, и каждая переменная, передаваемая в метод, получает свой собственный указатель в стеке. на эту ссылку в памяти, но не думаю, что это заставит нас исчерпать память. Мы работаем в PCF и не видим скачков памяти или чего-либо еще в течение этого времени. Память постоянна около 50%. Я также попытался использовать CopyOnWriteArrayList (потокобезопасный) вместо ArrayList, но проблема все еще существует.

Вопросы:

Любая идея, почему @Async метод будет отбрасывать элементы в аргументе метода? Список никогда не изменяется после создания, так почему же предметы исчезают? Почему первый элемент всегда исчезает? Почему не второй предмет? Почему оба исчезли бы?


Редактировать: Таким образом, этот вопрос не имел ничего общего с @Async в конце. Я нашел глубоко вложенный код, который удалял элементы из списка, в результате чего элементы go отсутствовали.

1 Ответ

1 голос
/ 15 февраля 2020

То, что вы сказали правильно, Java действительно является передачей по ссылке. Изменения в вашем списке должны определенно происходить из-за какого-то другого кода, который изменяет этот список во время выполнения потоков. Нет другого способа, которым объект изменил бы свои значения. Вы должны исследовать код в следующем разделе, чтобы определить, есть ли что-то, что изменяет список.

    -> Print items from list --- eventually drops items here always the first item, sometimes both.
    -> code following this might be changing the list. 

Поскольку AsyncService будет выполнять свой код асинхронно и в то же время, другой код модифицирует список .

Вы можете также сделать параметры метода равными final.

...