Проблемный многопоточный код

207
16 июля 2017, 10:46

У меня есть такой участок кода:

private List<NtId> getNtIds(List<String> ids) {
    List<NtId> ntIdList = new CopyOnWriteArrayList<>();
    int step = 10000;
    int stepsNumber = ids.size() / step + ids.size() % step == 0 ? 0 : 1;
    CountDownLatch countDownLatch = new CountDownLatch(stepsNumber);
    for (int i = 0; i < stepsNumber - 1; ++i) {
        int current = i * step;
        new Thread(() -> {
            ntIdList.addAll(ntIdRepository.findDistinctByNtIdIn(ids.subList(current, current + step)));
            countDownLatch.countDown();
        }).start();
    }
    int lastStep = stepsNumber * step;
    new Thread(() -> {
        ntIdList.addAll(ntIdRepository.findDistinctByNtIdIn(ids.subList(lastStep, lastStep + ids.size() % step)));
        countDownLatch.countDown();
    }).start();
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return ntIdList;
}

Смысл его заключается в том, что на вход поступает список из id и по ним надо выгрузить объекты. База данных не принимает список более 1000 значений и поэтому, чтобы ускорить процесс делаю обработку во многих потоках.

Проблема в том, что при изменениях переменной step меняется и результат, чего быть не должно. В чем я ошибаюсь и как можно улучшить этот участок ?

Answer 1

Возможно вам подойдет вот такой вариант.

private static List<NtId> getNtIds(List<String> ids) {
    int step = 100;
    return split(ids, step).parallel()
            .map(l -> ntIdRepository.findDistinctByNtIdIn(l))
            .flatMap(List::stream)
            .collect(Collectors.toList());
}

Этот метод я взял тут Partition a Java 8 Stream. Но вы можете использовать аналогичный из Guava или любой другой библиотеки.

private static Stream<List<String>> split(List<String> list,  int size) {
    int parts = (list.size() - 1) / size;
    return IntStream.range(0, parts + 1).mapToObj(n -> list.subList(n * size, n == parts ? list.size() : (n + 1) * size));
}

Вот вариант с использованием Future

private static List<NtId> getNtIds(List<String> ids) {
    // размер pool можно подобрать
    ExecutorService executor = Executors.newFixedThreadPool(10);
    List<Future<List<NtId>>> futures = new ArrayList<>();
    int step = 100;
    int parts = (ids.size() - 1) / step;
    for (int i = 0; i < parts + 1; i++) {
        final List<String> subList = ids.subList(i * step, i == parts ? ids.size() : (i + 1) * step);
        futures.add(executor.submit(() -> ntIdRepository.findDistinctByNtIdIn(subList)));
    }
    List<NtId> ntIdList = new ArrayList<>();
    for (Future<List<NtId>> future : futures) {
        try {
            ntIdList.addAll(future.get());
        } catch (InterruptedException | ExecutionException e) {
            // игнорирю
        }
    }
    executor.shutdown();
    return ntIdList;
}
READ ALSO
Маcштабирование текстуры в PolygonRegion

Маcштабирование текстуры в PolygonRegion

Суть проблемы такова: имеется polygonRegion в котором содержится данная текстура (рис1)

210
Выравнивание camel routes на Java DSL в intellij-idea

Выравнивание camel routes на Java DSL в intellij-idea

Поискал по интернетам и не нашёл никаких плагинов для intellij-idea которые будут выравнивать camel rout'ы в "правильную" иерархию, как например делает...

254
NetBeans IDE 8.2

NetBeans IDE 8.2

Уважаемые программисты , подскажите , пожалуйста , как создать апплет в NetBeans IDE 82?

276