Подтвердить что ты не робот

Синхронизированный vs ReentrantLock по производительности

Я прошел через несколько неожиданностей, когда дело доходит до реализации Queue для многопоточной системы. Вот: -

Сценарий: - 1 производитель, 1 потребитель: - Производитель помещает целое число в очередь. Пользователь просто удаляет его из очереди.

Основная структура данных очереди: - TreeSet (который я никогда не думал использовать), LinkedList, LinkedBlockingQueue (с неопределенным размером)

Код: - TreeSet как очередь: -

while (i < 2000000) {
        synchronized (objQueue) {

            if (!(objQueue.size() > 0)) {
                try {
                    objQueue.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            Integer x = objQueue.first();
            if (x != null) {
                objQueue.remove(x);
                ++i;
            }
        }
    }

EDIT: -

      while (i < 2000000) {
        synchronized (objQueue) {
            objQueue.add(i);
            ++i;
            objQueue.notify();
        }
    }

Для LinkedBlockingQueue: -

     while (i < 2000000){
        try {
            objQueue.put(i);
            ++i;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            Thread.currentThread().interrupt();
        }
    }

      while (i < 2000000) {
        try {
            objQueue.take();
            ++i;

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            Thread.currentThread().interrupt();
        }
    }

Для LinkedList: - аналогичный код с синхронизированным.

Вопросы: -

1) Когда я измерил производительность через визуальную виртуальную машину, я заметил, что для кода производителя TreeSet работает лучше, чем LinkedBlockingQueue и LinkedList, хотя для этого требуется время O (log n), создание объектов в связанных структурах значительные накладные расходы. Почему теория отличается от практики? Почему мы предпочитаем связывать структуры массива над структурами дерева в реализациях очереди?

2) Синхронизированный выдается как явный выигрыш против ReeentrantLock, потому что TreeSet работает лучше, чем LinkedList, который работает лучше, чем LinkedBlockingQueue. Я хотел бы приложить результаты Visual VM. Это не в голосах со статьей, http://www.ibm.com/developerworks/java/library/j-jtp10264/index.html

Операции выполняются на

Dell Vostro 1015, Core 2 Duo 2.10, 2GB Ram с 32-разрядной операционной системой и

JVM: виртуальная машина клиента HotSpot (TM) Java (20.1-b02, смешанный режим) Java: версия 1.6.0_26, поставщик Sun Microsystems Inc.

4b9b3361

Ответ 1

1. ReentrantLock может быть более целесообразным использовать, если вам нужно реализовать поток, который перемещает связанный список, блокируя следующий node, а затем разблокируя текущий node.

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

Для правильного сравнения производительности см. это:

http://lycog.com/concurency/performance-reentrantlock-synchronized/

Ответ 2

  • Поскольку ваш тест ошибочен: в реальном случае использования время, затрачиваемое на производство и потребление элементов из очереди, гораздо важнее времени, необходимого для добавления и удаления элемента в очередь из очереди, Таким образом, сырая производительность очереди не так важна. BTW, код показывает только, как вы берете элементы из первой реализации очереди, а не как их добавлять. Более того, выбор соответствующей структуры не производится на основе производительности, а по поведению. Если вы хотите что-то параллельное, вы выбираете блокирующую очередь, потому что она реализована для вас и не имеет таких ошибок, как ваш код. Если вы хотите FIFO (который часто вам нужен), вы не будете выбирать TreeSet.

  • Если вы хотите сравнить синхронизированный или ReentrantLock, вы не должны использовать одну структуру данных для одной, а другую структуру данных для другой. Раньше ReentrantLock был быстрее, но сейчас они находятся на одном уровне (если я верю, что говорит Брайан Гетц в JCIP). Во всяком случае, я бы выбрал один из них по соображениям безопасности/возможности. Не по соображениям производительности.