Многопоточность с Java Executor - PullRequest
2 голосов
/ 22 октября 2010

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

Вот основной метод

public static void main(String[] args) {

     //Assume that I have request object that contain arrayList of names
     //and VectorList is container for each request result

     ExecutorService threadExecutor = Executors.newFixedThreadPool(3);
     Vector<Result> vectorList = new Vector<Result();

     for (int i=0;i<request.size();i++) {
          threadExecutor.execute(new QueryTask(request.get(i).getNames, vectorList)
     }

      threadExecutor.shutdown();

      response.setResult(vectorList)

}

А вот и класс QueryTask

public QueryTask() implements Runnable {

    private String names;
    private Vector<Result> vectorList;

    public QueryTask(String names, Vector<Result> vectorList) {
          this.names = names;
          this.vectorList = vectorList;
    }

    public void run() {
         // do something with names, for example, query database
         Result result = process names;

         //add result to vectorList
         vectorList.add(result);
    }


}

Итак, основываясь на приведенном выше примере, я хочу создать пул потоков для всех данных в запросе, запустить его одновременно и добавить результат в VectorList. И в конце процесса я хочу, чтобы все результаты уже были в списке Вектор.

Я продолжаю получать противоречивый результат в ответе. Например, если я передаю запрос с 10 именами, я получаю только 3 или 4, а иногда и ничего в ответе. Я ожидал, что если я пройду 10, я получу 10 обратно.

Кто-нибудь знает, в чем причина проблемы?

Любая помощь будет признательна.

Спасибо

Ответы [ 3 ]

3 голосов
/ 22 октября 2010

Простое решение - добавить вызов в ExecutorService.awaitTermination ()

public static void main(String[] args) {

     //Assume that I have request object that contain arrayList of names
     //and VectorList is container for each request result

     ExecutorService threadExecutor = Executors.newFixedThreadPool(3);
     Vector<Result> vectorList = new Vector<Result();

     for (int i=0;i<request.size();i++) {
          threadExecutor.execute(new QueryTask(request.get(i).getNames, vectorList)
     }

      threadExecutor.shutdown();
      threadExecutor.awaitTermination(aReallyLongTime,TimeUnit.SECONDS);

      response.setResult(vectorList)

}
2 голосов
/ 22 октября 2010

Вам необходимо заменить threadExecutor.shutdown(); на threadExecutor.awaitTermination();. После вызова threadExecutor.shutdown() вам необходимо также позвонить threadExecutor.awaitTermination().Первый является неблокирующим вызовом, который просто инициирует отключение, тогда как последний является блокирующим вызовом, который фактически ожидает завершения всех задач.Поскольку вы используете первое, вы, вероятно, вернетесь до того, как все задачи будут завершены, поэтому вы не всегда получаете все свои результаты.Java API не слишком понятен, поэтому кто-то подал ошибку по этому поводу.

0 голосов
/ 22 октября 2010

Здесь как минимум 2 вопроса.

  1. В своей главной работе вы закрываете ExecutorService, а затем сразу пытаетесь получить результаты. Служба executor выполнит ваши задания асинхронно, поэтому есть очень хороший шанс, что все ваши задания еще не выполнены. Когда вы вызываете response.setResult (vectorList), vectorList заполнен не полностью.

2. Вы одновременно получаете доступ к одному и тому же объекту Vector из всех ваших исполняемых файлов. Это может вызвать ConcurrentModificationExceptions, или просто разбить материал в векторе. Вам нужно либо вручную синхронизировать вектор внутри QueryTask, либо вместо этого передавать потокобезопасный контейнер, например, Collections.synchronizedList( new ArrayList() );

...