Как вернуть карту из функции Callable Future в Java

В моей весенней загрузочной программе я пытаюсь использовать функцию Callable Future для многопроцессорной обработки. Чтобы быть более точным, внутри loop я открыл несколько потоков и получил список карт из функции. После этого распечатываю полученный результат. К сожалению, выдает ошибку Method threw 'java.util.concurrent.ExecutionException' exception. Внутри подробное сообщение NullPointerException. Я пробовал несколько способов, ни один из которых не работает.

public class MyCallable implements Callable<List<Map<String, Object>>> {

    @Autowired
    @Qualifier("jdbcMaster")
    JdbcTemplate jdbcTemplate;

    private String SQL_QUERY;

    public MyCallable(){
    }

    public MyCallable(String SQL_QUERY){
        this.SQL_QUERY = SQL_QUERY;
    }

    @Override
    public List<Map<String, Object>> call() throws Exception {
        List<Map<String, Object>> ph_list = jdbcTemplate.queryForList(SQL_QUERY);
        return ph_list;
    }
}

        Integer listSize = regionFilials.size();
        ExecutorService service = Executors.newFixedThreadPool(listSize);
        List<Future<List<Map<String, Object>>>> resultList = new ArrayList<>();

        for (int i=0; i<listSize; i++){
            filialId = "'" + regionFilials.get(i) + "'";
            SQL_RESULT = SQL_SPECIAL_INCOME.replace("?", filialId);

            MyCallable myCallable  = new MyCallable(SQL_RESULT);
            Future<List<Map<String, Object>>> result = service.submit(myCallable);
            resultList.add(result);
        }

       for (Future<List<Map<String, Object>>> futures : resultList){

           try {
               if (futures.isDone()) {
                   try {
                       System.out.println("Name: " + futures.get(20, TimeUnit.SECONDS));
                   } catch (TimeoutException e) {
                       e.printStackTrace();
                   }
               }

           } catch (InterruptedException e) {
               e.printStackTrace();
           } catch (ExecutionException e) {
               e.getCause();
           }

       }

Когда я пытаюсь получить результат оператора select SQL_RESULT обычным способом, он дает правильный результат. Проблема не в SQL. Я предполагаю, что я неправильно улавливаю будущий результат или неправильно реализую callable future.


person Abdusoli    schedule 25.05.2020    source источник
comment
не могли бы вы поместить сюда трассировку стека? Я также рекомендую вам запускать код без параллелизма, чтобы убедиться, что проблема не вызвана какой-то другой проблемой в логике, т.е. ответ базы данных отличается от того, что вы ожидаете.   -  person GiorgosDev    schedule 25.05.2020
comment
На самом деле он не дает ошибки. Когда я помещаю отладку в строку ``` futures.get(20, TimeUnit.SECONDS) ``` и вижу Evaluate Expression в поле результата, он показывает ошибку выше.   -  person Abdusoli    schedule 25.05.2020
comment
Вы пытались увеличить время ожидания, т.е. поставить futures.get(60, TimeUnit.SECONDS) или просто использовать futures.get()?   -  person GiorgosDev    schedule 25.05.2020
comment
Я использовал как версию с таймаутом, так и версию без таймаута. Оба не работают   -  person Abdusoli    schedule 25.05.2020
comment
но если вы запустите без фьючерсов и параллелизма, вы получите ожидаемый результат?   -  person GiorgosDev    schedule 25.05.2020
comment
да, я получил ожидаемый результат   -  person Abdusoli    schedule 25.05.2020
comment
Кажется интересным, просто предположение, есть ли в MyCallable аннотация? правильно ли введена зависимость jdbcTemplate?   -  person GiorgosDev    schedule 25.05.2020


Ответы (1)


Насколько я вижу, MyCallable не имеет аннотаций и, кроме того, он не создается Spring, так что это означает, что зависимость jdbcTemplate не будет автоматически внедрена. Пожалуйста, проверьте в отладке - он должен быть нулевым. Я рекомендую один из следующих вариантов:

  1. Добавьте зависимость JdbcTemplate к классу, в котором вы создаете вызываемые объекты. Установите JdbcTemplate в конструкторе MyCallable или создайте установщик для JdbcTemplate и задайте его вручную.
  2. Оставьте все как есть, просто убедитесь, что аннотация @Component и @Scope установлены на прототип для MyCallable. Затем вы можете использовать context.getBean(MyCallable.class) для создания экземпляра MyCallable с введенным JDBCTemplate.

Я бы порекомендовал первый подход, так как в MyCallable как bean-компоненте нет особого смысла - он никуда не внедряется, поэтому второй подход не распространен и делает код не таким чистым.

person GiorgosDev    schedule 25.05.2020
comment
Да, вы правы, jdbcTemplate имеет значение null, когда я проверяю отладку - person Abdusoli; 26.05.2020
comment
Теперь это работает. Первый способ, который вы рекомендовали, сработал. Спасибо за помощь. Ценить это! - person Abdusoli; 26.05.2020