Как назначить задачу CompletableFuture, чтобы после ее выбора ее не нужно было поднимать снова

У меня есть несколько таких задач:

            public static String task1()    
            public static String task2() 
            public static String task3()
            public static String task4()
            public static String task5()
            public static String task6()

Я хочу выполнить эти задачи, используя CompletableFuture параллельно, но асинхронно с исполнителем:

    CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> executeTask(), executor);   
    CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> executeTask(), executor);
    CompletableFuture<Object> future3 = CompletableFuture.supplyAsync(() -> executeTask(), executor);

executeTask() - это метод, который извлекает задачу для выполнения, теперь проблема в том, что когда я начинаю выполнять приведенный выше код, тогда задача1() выбирается всеми будущими1, будущими2 и будущими3, а задача2 выбирается всеми, потому что все фьючерсы работают параллельно и асинхронно. То, что я хотел, - как только задача будет выбрана любым Future Object, она не должна быть выбрана другими. Как мне этого добиться. Любая помощь будет оценена по достоинству. Спасибо.

Вот код executeTask(), что он делает: Существует карта (статическая TreeMap> map = new TreeMap‹>();), которая содержит имя метода и метод, которые должны быть возвращены как задачи, такие как задача1, задача2 и т. д.. Теперь, что я здесь делаю: я повторяю карту и нахожу ту запись, которая не имеет статуса ключа, что означает, что эта задача может быть выполнена и возвращена, и перед возвратом я помещаю ключ состояния, чтобы его нельзя было подобрать очередной раз. Теперь все фьючерсы работают как асинхронные, поэтому все они выбирают задачу1 вместе и так далее.

public static Object executeTask()
{
    Object result = null;

    try
    {
        Method method = null;

        for(Entry<String, HashMap<String, Method>> en : map.entrySet())
        {
            if(!en.getValue().containsKey("status"))
            {
                System.out.println("Found free task: "+en.getKey().toString());
                method = en.getValue().get(en.getKey());
                en.getValue().put("status", ConcurrencyPoC_CompletableFuture.class.getMethod("toString"));

                break;
            }
        }

        if(method != null)
        {
            System.out.println("Executing : "+method.getName());
            result = (String) method.invoke(new ConcurrencyPoC_CompletableFuture());
        }

    }catch(Exception e)
    {
        e.printStackTrace();
    }

    return result;
}

person Pankaj Kumar Katiyar    schedule 18.09.2016    source источник


Ответы (1)


Сделайте так, чтобы executeTask() возвращал актуальную задачу только один раз и задачу, которая ничего не делает после многократного вызова.

Вы можете использовать синхронизацию, блокировку или атомарную ссылку на задачу (я бы сделал последнюю)

person Peter Lawrey    schedule 18.09.2016
comment
executeTask() возвращает задачу, которую должен забрать Futures, в методе executeTask() возвращается рекурсия, так что каждый раз должна возвращаться задача, пока она существует. Я не уверен, как ограничить это. некоторая дополнительная информация была бы полезна. Спасибо. - person Pankaj Kumar Katiyar; 18.09.2016
comment
@PankajKatiyar, если вы хотите, чтобы задача выполнялась только один раз, вы должны вернуть эту задачу только один раз. Вы говорите, что не можете изменить код? Я не уверен, что мешает вам. - person Peter Lawrey; 18.09.2016
comment
Я добавил код executeTask, который все время вызывается для возврата задачи, я не уверен, что я могу там изменить. Не могли бы вы взглянуть на это еще раз, пожалуйста, - person Pankaj Kumar Katiyar; 18.09.2016
comment
@PankajKatiyar, где устанавливается карта? Вы можете передать атомарное целое число, которое вы увеличиваете, и делать что-то только в том случае, если счетчик равен 0. - person Peter Lawrey; 18.09.2016
comment
Я до сих пор не могу найти решение, позвольте мне описать это следующим образом: у меня есть карта, содержащая TaskName и Task, для их выполнения я использовал три экземпляра CompletableFuture, эти будущие выполняют один и тот же метод executeTask (). executeTask() выполняет итерацию карты и получает задачу, которая имеет ключ = статус и выполняется. Теперь проблема связана с параллельным выполнением, все фьючерсы выполняют executeTask() вместе, и одна и та же задача возвращается ко всем фьючерсам. Теперь я не уверен, где мне использовать AtomicInt, я пытался, но не работал, если вы можете указать мне, где поставить проверку. Спасибо - person Pankaj Kumar Katiyar; 21.09.2016
comment
Также я не могу заставить executeTask() возвращать задачу только один раз, потому что это метод, который перебирает карту и возвращает задачи. - person Pankaj Kumar Katiyar; 21.09.2016
comment
@PankajKatiyar вы передаете одно и то же атомарное целое число всем трем вызовам. Только один поток сможет увеличить значение от 0 до 1. - person Peter Lawrey; 22.09.2016