Подтвердить что ты не робот

В чем разница между ExecutorService.submit и ExecutorService.execute в этом коде на Java?

Я учусь использовать ExectorService для объединения threads и отправки задач. У меня есть простая программа ниже

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


class Processor implements Runnable {

    private int id;

    public Processor(int id) {
        this.id = id;
    }

    public void run() {
        System.out.println("Starting: " + id);

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("sorry, being interupted, good bye!");
            System.out.println("Interrupted "+Thread.currentThread().getName());
            e.printStackTrace();    
        }

        System.out.println("Completed: " + id);
    }
}


public class ExecutorExample {

    public static void main(String[] args) {
        Boolean isCompleted=false;

        ExecutorService executor = Executors.newFixedThreadPool(2);

        for(int i=0; i<5; i++) {
            executor.execute(new Processor(i));
        }

        //executor does not accept any more tasks but the submitted tasks continue
        executor.shutdown();

        System.out.println("All tasks submitted.");

        try {
            //wait for the exectutor to terminate normally, which will return true
            //if timeout happens, returns false, but this does NOT interrupt the threads
            isCompleted=executor.awaitTermination(100, TimeUnit.SECONDS);
            //this will interrupt thread it manages. catch the interrupted exception in the threads 
            //If not, threads will run forever and executor will never be able to shutdown.
            executor.shutdownNow();
        } catch (InterruptedException e) {
        }

        if (isCompleted){
        System.out.println("All tasks completed.");
       }
        else {
            System.out.println("Timeout "+Thread.currentThread().getName());
        }
    }
        }

Он ничего не делает, но создает два threads и отправляет всего 5 задач. После того, как каждый thread завершает свою задачу, он принимает следующую. В приведенном выше коде я использую executor.submit. Я также изменил на executor.execute. Но я не вижу разницы в выводе. Чем отличаются методы submit and execute? Это то, что говорит API

Метод submit расширяет базовый метод Executor.execute(java.lang.Runnable), создавая и возвращая Future, который можно использовать для отмены выполнения и/или ожидания завершения. Методы invokeAny и invokeAll выполняют наиболее часто используемые формы массового выполнения, выполняя набор задач, а затем ожидая завершения хотя бы одной или всех задач. (Класс ExecutorCompletionService можно использовать для написания пользовательских вариантов этих методов.)

Но мне не ясно, что именно это означает?

4b9b3361

Ответ 1

Как вы видите из JavaDoc execute(Runnable) ничего не возвращает.

Однако submit(Callable<T>) возвращает объект Future, который позволяет вам программно отменить выполняемый поток позже, а также получить T, который возвращается, когда завершается Callable. Подробнее см. JavaDoc of Future.

Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);

Кроме того, if future.get() == null и не вызывает никаких исключений, тогда Runnable успешно выполнен

Ответ 2

Разница в том, что execute просто запускает задачу без каких-либо дополнительных атак, тогда как submit возвращает объект Future для управления задачей. Вы можете сделать следующее с объектом Future:

  • Отменить задачу преждевременно, используя метод cancel.
  • Дождитесь завершения выполнения задачи с помощью get.

Интерфейс Future более полезен, если отправить пул Callable в пул. Возвращаемое значение метода call будет возвращено при вызове Future.get. Если вы не поддерживаете ссылку на Future, нет никакой разницы.

Ответ 3

execute: использовать его для огня и забыть звонки

submit: Используйте его, чтобы проверить результат вызова метода и принять соответствующие меры в отношении возражения Future возвращенного вызовом

Основное отличие: обработка Exception

submit() скрывает необработанное Exception в самой структуре.

execute() выбрасывает необработанное Exception.

Решение для обработки исключений с submit()

  1. Оберните ваш Callable or Runnable code in try{} catch{} block

    ИЛИ ЖЕ

  2. Сохраняйте future.get() call in try{} catch{} block

    ИЛИ ЖЕ

  3. реализовать свой собственный ThreadPoolExecutor и переопределить метод afterExecute

Относительно тура другие вопросы на

invokeAll:

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

invokeAny:

Выполняет заданные задачи, возвращая результат одного успешно выполненного задания (т.е. Без исключения), если оно выполнено до истечения заданного времени ожидания.

Используйте invokeAll если вы хотите дождаться завершения всех отправленных задач.

Используйте invokeAny если вы ищете успешное завершение одной задачи из N представленных задач. В этом случае выполняемые задачи будут отменены, если одна из задач завершится успешно.

Связанный пост с примером кода:

Выберите между отправкой ExecutorService и выполнением ExecutorService

Ответ 4

Submit - Возвращает объект Future, который можно использовать для проверки результата отправленной задачи. Может использоваться для отмены или для проверки isDone и т.д.

Выполнить - ничего не возвращает.

Ответ 5

в основном, оба вызова выполняются, если вы хотите в будущем объект, вы должны вызвать здесь метод submit() из документа

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}


public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

как вы можете видеть, у java действительно нет никакого способа запустить поток, кроме вызова метода run(), IMO. так как я также обнаружил, что Callable.call() вызывается внутри метода run(). следовательно, если объект может быть вызван, он все равно вызовет метод run(), который inturn вызовет метод call() из doc.

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

Ответ 6

Основное различие между методами submit() и execute() заключается в том, что ExecuterService.submit() может возвращать результат вычисления, поскольку он имеет тип возвращаемого значения Future, но метод execute() не может ничего возвратить, поскольку его тип возвращаемого значения void. Базовым интерфейсом в среде Java 1.5 Executor является интерфейс Executor, который определяет метод execute (Runnable task), основной целью которого является отделение задачи от ее выполнения.

Любая задача, переданная Исполнителю, может быть выполнена одним и тем же потоком, рабочим потоком из пула потоков или любым другим потоком.

С другой стороны, метод submit() определен в интерфейсе ExecutorService, который является подчиненным интерфейсом Executor, и добавляет функциональность завершения пула потоков вместе с добавлением метода submit(), который может принять задачу Callable и вернуть результат. вычисления.

Сходства между execute() и submit() также:

  1. Оба метода submit() и execute() используются для отправки задачи в среду Executor для асинхронного выполнения.
  2. Оба submit() и execute() могут принять задачу Runnable.
  3. Вы можете получить доступ к submit() и execute() из интерфейса ExecutorService, поскольку он также расширяет интерфейс Executor, который объявляет метод execute().

Помимо того, что метод submit() может возвращать output, а execute() не может, ниже приведены другие заметные различия между этими двумя ключевыми методами среды Executor Java 5.

  1. Submit() может принять как Runnable, так и Callable задачу, но execute() может принять только Runnable задачу.
  2. Метод submit() объявлен в интерфейсе ExecutorService, а метод execute() объявлен в интерфейсе Executor.
  3. Возвращаемый тип метода submit() - это объект Future, но возвращаемый тип метода execute() является недействительным.