2016-02-24 2 views
2

У меня есть этот метод:Как вызвать метод в многопоточном способе, который возвращает элементы списка

public List<String> composeList (DataBaseObject dBO) { 
    List<String> valueList = new ArrayList<>(); 
     for (String separatedFieldName : separatedFieldNames) { 
      object = PropertyUtils.getProperty(object, separatedFieldName); 
      valueList.add(object.toString()); 
     }       
    } 

У меня есть список из 1000 объектов ДБЫ и хотел бы назвать этот метод в несколько -простой путь.

Но возвращение этого метода также входит в список

Вот звонящий:

List<List<String>> valueLists = new ArrayList<>(); 
    for (DataBaseObject dBO : listOfDBOs) 
    valueLists.add(composeList(dBOObject)); 

Поскольку машины теперь дни имеют несколько ядер, мне было интересно, как я могу использовать их. Например, как я могу вызвать composeList в parellel и сохранить результаты в одном ArrayList.

Я знаю, что могу использовать Collections.SynchronizedList, но тогда время выполнения composeList настолько мало, что я в конечном итоге добавлю элементы в последовательность и даже будучи многопоточными, это все равно будет последовательным выполнением, так как каждый add будет поместите блокировку в Синхронизированный список.

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

+1

Я не думаю, что вы можете спокойно записывать объект одновременно. Вы могли бы вызвать свой список во время запуска другой задачи, но не одновременно выполнять два задания одновременно одного и того же списка. Вот почему SynchronizedLists - это, по сути, последовательное поведение, когда это используется, это единственный безопасный способ сделать это. – DonyorM

+0

Как я уже сказал, это не проблема, связанная с населением списка. Может быть, вы тоже можете предложить что-то с дизайном. К сожалению, мне нужно дождаться завершения списка, чтобы следующая задача выполнялась. Таким образом, не может вызвать что-либо еще в среднее время. –

+1

В вашем примере неясно, почему добавление к 'valueList' выходит за пределы цикла. Насколько я понимаю, вы собираетесь добавить все значения всех полей? –

ответ

-1

Подробнее о ExecutorService и ForkJoin рамки в java. Это может помочь вам достичь того, чего вы хотите.

спасибо.

1

Java 8 параллельных потоков предназначены именно для этой ситуации.

List<String> dbFieldValues = dbObjectList.parallelStream() 
    .flatMap(seperatedFieldNames().parallelStream() 
     .map(fn -> PropertyUtils.getProperty(db, fn).toString())) 
    .collect(Collectors.toList()); 

Предполагая, что коллекция seperatedFieldNames поддерживает параллельные потоки (например, ArrayList) это будет использовать несколько потоков без необходимости создавать их самостоятельно.

Обратите внимание, что это предполагает отсутствие побочных эффектов до getProperty.

+0

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

0

Возможно, это решение немного «традиционный стиль» без каких-либо новых интересных вещей, как потока и т.д., но я хотел бы сделать что-то вроде следующие:

public class AnyClass { 

    private static final AtomicInteger index = new AtomicInteger(0); 
    private static final Object lock = new Object();  

    public class ComposerThread implements Runnable { 

     private List<DataBaseObject> dboList; 
     private List<List<String>> valueList; 
     private List<String> fieldNames; 

     public MyThread(List<DataBaseObject> dboList, List<List<String>> valueList, 
         List<String> fieldNames) { 
      this.valueList= valueList; 
      this.dboList = dboList; 
      this.fieldNames = fieldNames; 
     } 

     public void run() { 
      int i = index.getAndIncrement(); //thread takes next unprocessed index 
      while(i<dboList.size()){ 
       DataBaseObject object = dboList.get(i); 
       List<String> list = new ArrayList<>(); 
       for (String separatedFieldName : fieldNames) { 
        Object object = PropertyUtils.getProperty(object, separatedFieldName); 
        list.add(object.toString()); 
       } 

       synchronized (lock) { //addition synchronized 
        valueList.add(list); 
       } 
       i = index.getAndIncrement(); //thread takes next unprocessed index 
      } 
     } 
    } 
    .... 
} 

Обратите внимание, что AtomicInteger index и Object lock должны быть final static, из-за использования в синхронизации. Теперь вы можете использовать ComposerThread внутренний класс в одном родительском классе:

public class AnyClass{ 

    .... 

    private List<List<String>> composeValueList(List<DataBaseObject> dboList, 
               List<String> fieldNames, int threadCount) { 

     index.set(0);//reset index before process dboList 
     List<List<String>> valueList = new List<List<String>>(); 

     Thread [] pool = new Thread[threadCount]; 
     for(int i=0; i<pool.length; i++){ 
      pool[i] = new Thread(new ComposerThread (objectList, valueList, fieldNames)); 
      pool[i].start(); 
     } 
     for(Thread thread : threadPool){ 
      thread.join(); //just wait while all will be done 
     } 
     return valueList; 
    } 
} 

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

Смежные вопросы