Как правильно использовать threadpool и получить результат из потока? - PullRequest
1 голос
/ 19 августа 2011

Я хочу попробовать многопоточное программирование (новое для меня), и у меня есть несколько вопросов.

Я использую ThreadPoolTaskExecutor с TestTask, который реализует Runnable и runметод, который спит в течение X секунд.Все прошло гладко, и все мои TestTask были выполнены в другом потоке.Хорошо.Сложность в том, что я хочу узнать результат операции, выполненной в потоке.Поэтому я прочитал кое-что в Google / stack / etc и попытался использовать Future.И это больше не работает: /

Я использую метод get, чтобы получить (о, правда?) Результат метода call, и эта часть работает, но TestTask выполняются один за другим (и не в то же время, как раньше).Наверное, я что-то не правильно понял, но не знаю, что ... и поэтому мне нужна ваша помощь!

Класс, который запускает тест:

public void test(String test) {

    int max = 5;
    for (int i = 0; i < max; i++) {
        TestThreadService.launch(i);
    }
    System.out.println("END");

}

Класс TestThreadService:

public class TestThreadService {

private ThreadPoolTaskExecutor taskExecutor;

public void launch(int i) {
    System.out.println("ThreadNumber : "+i);
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false);
    TestTask testTask = new TestTask(i);
    FutureTask<Integer> futureOne = new FutureTask<Integer>(testTask);
    taskExecutor.submit(futureOne);
    try {
        Integer result = futureOne.get();
        System.out.println("LAUNCH result : "+i+" - "+result);
    } catch (Exception e) {
        e.printStackTrace();
    }
  }

public void setTaskExecutor(ThreadPoolTaskExecutor taskExecutor) {
  this.taskExecutor = taskExecutor;
}

}

И класс TestTask:

public class TestTask implements Callable<Integer> {

public Integer threadNumber;
private Integer valeur;

  public TestTask(int i) {
    this.threadNumber = i;
  }

  public void setThreadNumber(Integer threadNumber) {
    this.threadNumber = threadNumber;
  }

    @Override
    public Integer call() throws Exception {
        System.out.println("Thread start " + threadNumber);
        // generate sleeping time
        Random r = new Random();
        valeur = 5000 + r.nextInt(15000 - 5000);
        System.out.println("Thread pause " + threadNumber + " " + valeur);
        try {
            Thread.sleep(valeur);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread stop" + threadNumber);
        return this.valeur;
    }

}

Я неплох в Java, но я впервые пытаюсь использовать другой поток, такя добрый для меня.

Что я делаю не так?

Спасибо!

Ответы [ 2 ]

1 голос
/ 19 августа 2011

В вашем test методе

TestThreadService.launch(1);

, вероятно, должно быть

TestThreadService.launch(i);

Главное, хотя это вызов

Integer result = futureOne.get();

в launch метод.Вызов get() для FutureTask является блокирующей операцией, то есть он не вернется, пока задача не будет завершена.Вот почему вы видите серийное поведение.Вариант использования, который вы эмулируете (обрабатывает множество действий и ожидает их завершения), не подходит для ThreadPoolTaskExecutor.У него нет функции «соединения», которой обладают необработанные потоки.Это существо сказало, что вы хотите сделать что-то вроде

public Future<Integer> launch(int i) {
    System.out.println("ThreadNumber : "+i);
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false);
    TestTask testTask = new TestTask(i);
    FutureTask<Integer> futureOne = new FutureTask<Integer>(testTask);
    return taskExecutor.submit(futureOne);
  }

И в вашем методе испытаний

public void test(String test) {
    List<Future<Integer>> tasks = new ArrayList<Future<Integer>>();
    int max = 5;
    for (int i = 0; i < max; i++) {
        tasks.add(TestThreadService.launch(i));
    }
    for (Future<Integer> task : tasks) {
        System.out.println("LAUNCH result : " + task.get());
    }
    System.out.println("END");

}
0 голосов
/ 27 августа 2012

также вы можете переместить setWaitForTasksToCompleteOnShutdown (false) в другой метод, чтобы не вызывать его каждый раз при запуске потока, который, как я вижу, (не очень много потоков), но в другом сценарии с большим количеством задач:ненужная и дорогая работа.

Вы также можете создать публичный метод для службы, называемый: configure ();или, перед запуском ();прежде чем начать создавать темы.

Глюк!

...