Какая дополнительная задача выполняется при использовании ExecutorService? - PullRequest
0 голосов
/ 27 июня 2018

Я изучаю параллелизм Java. Так наткнулся на этот пример в сети за это. Я написал следующий код. Проблема в том, что, хотя задачи и выполняются, похоже, что выполняется нечто дополнительное. Так как мне узнать, что выполняется?

package com.test.executors;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.Logger;

class MyObject {
    private Integer number;
    private Integer result;

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public Integer getResult() {
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }
}

class FactorialCalculator implements Callable<MyObject> {

    private Integer number;

    public FactorialCalculator(Integer number) {
        this.number = number;
    }

    @Override
    public MyObject call() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " started...");
        MyObject object = new MyObject();
        object.setNumber(number);
        int result = 1;
        if (0 == number || 1 == number) {
            result = 1;
        } else {
            for (int i = 2; i <= number; i++) {
                result *= i;
                TimeUnit.SECONDS.sleep(1);
            }
        }
        object.setResult(result);
        System.out.println(Thread.currentThread().getName() + " done...");
        return object;
    }
}

public class ExecutorMain1 {

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(3);
        List<Future<MyObject>> results = new ArrayList<>();
        Random random = new Random();
        System.out.println("Starting Services...");
        for (int i = 0; i < 5; i++) {
            Integer number = random.nextInt(10);
            Future<MyObject> result = service.submit(new FactorialCalculator(number));
            results.add(result);
        }

        System.out.println("Done submitting tasks...");
        System.out.println("Will display results shortly...");

        for (Future<MyObject> future : results) {

            try {
                System.out.println("Number: " + future.get().getNumber() + "--> Result: " + future.get().getResult() + " Task Status: " + future.isDone());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Exiting main...");
    }
}

Выход -

Starting Services...
Done submitting tasks...
Will display results shortly...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-2 started...
pool-1-thread-2 done...
pool-1-thread-1 started...
pool-1-thread-1 done...
Number: 6--> Result: 720 Task Status: true
Number: 5--> Result: 120 Task Status: true
pool-1-thread-3 started...
pool-1-thread-3 done...
Number: 4--> Result: 24 Task Status: true
Number: 0--> Result: 1 Task Status: true
Number: 1--> Result: 1 Task Status: true
Exiting main...

После Exiting main... программа еще не закрывается. Это блокирует что-то. 5 заданий, которые представлены, также выполнены. Так что исполняется? Как мне это узнать?

Ответы [ 3 ]

0 голосов
/ 27 июня 2018

JVM не завершится, пока запущены потоки, не являющиеся демонами. А ваш ExecutorService создает рабочие потоки, не являющиеся демонами. Таким образом, чтобы JVM мог завершить работу, вам необходимо закрыть службу исполнителя. Позвонив по номеру shutdown() или shutdownNow(), поскольку все ваши задачи уже выполнены.

0 голосов
/ 27 июня 2018

Один небольшой комментарий к вашему "найденному коду": InterruptedException почти исключительно полезен в качестве запроса на завершение потока. Считать это нормальным исключением часто бывает ошибкой. Эта строка кода:

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

Возможно, это бесполезно, нет причин печатать трассировку стека только потому, что вас попросили выйти.

Кроме того, когда вы ловите InterruptedException, и вы НЕ БРОСАЕТЕ ЭТО, вы должны сбросить флаг прерывания для вашего потока.

} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

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

C.f. Брайан Гетц Java-параллелизм на практике

0 голосов
/ 27 июня 2018

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

service.shutdown();
System.out.println("Exiting main...");
...