Есть ли способ, где несколько потоков можно добавить в один и тот же список объектов? - PullRequest
0 голосов
/ 22 февраля 2020

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

Я пытался создать объект списка и передать его executorservice, но это создало бы несколько копий одного и того же списка, и в конце я вижу только 1 элемент, добавленный в список.

Примечание. Меня интересует только асинхронная запись в список. Мое чтение синхронизировано.

public class main{
      public static void main(String[] args)
    {

        ExecutorService taskExec = Executors.newFixedThreadPool(count); 
        List<JsonDocument> documents = new ArrayList<JsonDocument>();

        // this seems to be incorrect
        taskExec.submit(new test(documents, size));
    }
}

class test implements Runnable{

// this class will add JsonDocuments to list object

}

Как я могу заставить все потоки использовать / записывать в один и тот же объект списка?

Я новичок в многопоточности, любая помощь будет оценена .

Спасибо.

Обновление: я пытался использовать Collections.syncronizedList, но он все еще не работает для меня .. может быть, я не правильно его использую

public class App {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<JsonDocument> documents = Collections.synchronizedList(new ArrayList<JsonDocument>());

        ExecutorService taskExec = Executors.newFixedThreadPool(4); 

        taskExec.submit(new test(documents, size));

        for (JsonDocument json : documents) {
            System.out.println(json.toString());
        }


        while(!taskExec.isTerminated()) {
            taskExec.shutdown();
        }

    }
}

    class test implements Runnable {

        int size;
        List<JsonDocument> doc;

        createJson(List<JsonDocument> doc, int size){
            this.size = size;
            this.doc = doc;
        }

        public void run() {

            Hashtable<String, String> ht = new Hashtable<String, String>();

            for (int i=0; i<size; i++) {
                ht.put("key"+i, "key"+i);
            }

            String jsonString = JsonObject.from(ht).toString();

            doc.add(new JsonDoc);

        }
}

Пожалуйста, поправьте меня здесь.

Ответы [ 2 ]

3 голосов
/ 22 февраля 2020

Collections.syncronizedList должен выполнить эту работу, но с вашим кодом есть некоторые проблемы:

    taskExec.submit(new test(documents, size));

    for (JsonDocument json : documents) {
        System.out.println(json.toString());
    }


    while(!taskExec.isTerminated()) {
        taskExec.shutdown();
    }
  1. Вы передаете исполняемые файлы, но не ждете завершения перед печатью списка

  2. while(!taskExec.isTerminated()) - неправильный способ ожидания завершения

Вот модифицированный код:

    taskExec.submit(new test(documents, size));

    taskExec.awaitTermination(1, TimeUnit.MINUTES);// wait a minute for termination

    for (JsonDocument json : documents) {
        System.out.println(json.toString());
    }

    // This should be inside a finally block
    taskExec.shutdown();
2 голосов
/ 22 февраля 2020

for-loop зависит от операции, выполняемой потоками. Вы должны дождаться завершения всех потоков. Вы можете использовать taskExec.awaitTermination, предложенный Eugen. Но трудно установить время ожидания awaitTermination, вы можете передать какое-то большое значение, но решение не будет хорошо масштабироваться.

Если вы используете java 8 или более позднюю версию, используйте CompletableFuture:

CompletableFuture.runAsync(new test(documents, size), taskExec2)
  .thenAccept(documents -> documents.forEach(doc -> System.out.print(doc.toString())));

Если вы используете java 7, вы можете использовать Future

Future<Void> future = taskExec.submit(new test(documents, size));
submit.get();  // blocking operation
// your logic for-loop etc.

тестовый класс:

class test implements Callable<Void> {
   // constructor etc.

    public Void call() {    
       // your business logic

       return null;
    }
}

Обратите внимание, что результат synchronizedList является "синхронизированным", но не "параллельным". Одна фундаментальная проблема, заключающаяся в том, что многие операции List, основанные на индексах, сами по себе не являются атомами c и должны быть частью более широкой конструкции взаимного исключения.

...