Синхронизированная параллельная запись ArrayList

каждый. Чтобы протестировать ArrayList, возвращаемый методом Collections.synchronizedList(), я определил статический класс, как показано ниже.

static class ListWriter implements Runnable { 
    private List<Integer> list; 

    public ListWriter(List<Integer> list) { 
        this.list = list; 
    } 

    public void run() {  // I didn't use synchronized(list) {} block here.
        try { 
            for (int i = 0; i < 20; i++) { 
                list.add(i); 
                Thread.sleep(10); 
            } 
        } catch (Exception e) { 
            e.printStackTrace();
        }
    } 
} 

и метод тестирования, как показано ниже

private static void test1() throws Exception {
    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    Thread t1 = new Thread(new ListWriter(list)); 
    Thread t2 = new Thread(new ListWriter(list));

    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
    for (int i = 0; i < list.size(); ++i) { 
        System.out.println(list.get(i)); 
    } 
}

Результат обычно такой: 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19

Но иногда будет так:

0 0 1 1 2 3 2 3 4 5 4 5 6 7 6 8 7 9 8 10 9 11 10 12 11 13 12 14 13 15 14 15 16 17 16 17 18 19 18 19

Означают ли эти результаты, что процесс является потокобезопасным? Дело в том, что я не использовал синхронизированный блок в потоке записи, который явно требуется для перебора синхронизированного списка ArrayList, возвращаемого методом Collection.synchronizedList(). Итак, как вы думаете, процесс является потокобезопасным или мне все равно нужно использовать синхронизированный блок?


person magicbacon    schedule 08.08.2012    source источник


Ответы (4)


Выходные данные недетерминированы — они зависят от поведения планирования базовой операционной системы.
Тот факт, что иногда вы получаете определенную последовательность, — это просто совпадение. Ваш список синхронизируется при создании Collections.synchronizedList, поэтому вам не нужна дополнительная синхронизация.

Грубым тестом потокобезопасности вашего списка будет проверка того, что количество элементов, содержащихся в списке, равно 40 после выполнения обоих потоков.

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

person munyengm    schedule 08.08.2012

Метод add синхронизирован, поэтому вам не нужно добавлять в код дополнительную синхронизацию. Причина, по которой числа могут быть не в порядке, заключается в том, что 2 потока останавливаются с помощью Thread.sleep(), что не очень точно, поэтому возможно, что один поток немного опережает другой, создавая второй вывод.

Если вы удалите Thread.sleep(), вы получите еще больше вариантов вывода.

person assylias    schedule 08.08.2012

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

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

Проверьте javadoc< /а>.

person Nandkumar Tekale    schedule 08.08.2012

Целью потоков является выполнение независимых задач. Когда это не так, им приходится координировать свои действия, и это может быть накладным.

Что может быть удивительным, так это то, что вы не можете гарантировать ни порядок выполнения потоков, ни продолжительность их сна. Вы можете выполнить один поток до завершения, прежде чем начнется второй. У вас может произойти сбой вашей программы или машины, а поток(и) никогда не завершится.

Означают ли эти результаты, что процесс является потокобезопасным?

Это указывает на то, что потоки работают независимо, как и должны.

Дело в том, что я не использовал синхронизированный блок в потоке записи, который явно требуется для итерации по синхронизированному ArrayList, возвращаемому методом Collection.synchronizedList().

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

Итак, как вы думаете, процесс является потокобезопасным или мне все равно нужно использовать синхронизированный блок?

Нет. Если вы ожидаете постоянного порядка, не используйте потоки. Это будет проще и быстрее и каждый раз будет давать один и тот же результат. ;)

person Peter Lawrey    schedule 08.08.2012