Странное поведение параллелизма на Java 6 Mac OS X Lion - PullRequest
1 голос
/ 27 января 2012

Я экспериментировал с разницей между встроенными замками и java.util.concurrent.ReentrantLock уже некоторое время.Я нашел очень странную вещь.Рассмотрим следующий код:

public class WriteOnceRunAnywhere {

    private static long counter = 0;

    public static void main(String[] args) throws InterruptedException {

        final int numThreads = 2;
        final int numIterations = Integer.MAX_VALUE;

        Runnable inc = new Runnable() {
            public void run() {
                for (int i = 0; i < numIterations; i++) {

                    increment();

                    if (i % 10000000 == 0)
                        System.out.println(Thread.currentThread().getName());
                }
            }
        };

        for (int i = 0; i < numThreads; i++)
            new Thread(inc).start();
    }

    public static synchronized void increment() {
        counter++;
    }
}

Простая вещь, ничего необычного.Правильно?Бывает сломать!Скорее всего, когда вы запустите его, это не закончится.После некоторого пинг-понга между потоками вы увидите, что фактически работает только один поток.Другой зависает навсегда:

Нить-1 Нить-2 Нить-1 Нить-2 ... Нить-2 Нить-2 Нить-2 Нить-2 Нить-2Тема-2 Тема-2 Тема-2 Тема-2 Тема-2 ...

После этого процесс Java не может принять jvisualvm соединение.Загрузка процессора падает и постоянно остается на уровне около 1,0%.

Mac OS X Lion 10.7.2 (11C74), 2,53 ГГц Intel Core i5

Java-версия "1.6.0_29" Java (TM) SE Runtime Environment (сборка 1.6.0_29)-b11-402-11M3527) Java HotSpot (TM) 64-разрядная серверная виртуальная машина (сборка 20.4-b02-402, смешанный режим)

Может кто-нибудь сказать мне, что здесь происходит?

UPD Похоже, ошибка будет исправлена ​​в 1.6.30 см.

Ответы [ 3 ]

1 голос
/ 27 января 2012

Похоже, вы наблюдаете существующую ошибку в Mac OS 7 JDK 1.6. Вы можете увидеть ту же проблему, произошедшую здесь:

http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008778.html

Вы можете прочитать с самого начала на

http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008759.html

Наконец-то, похоже, есть разрешение для Open JDK 7.

http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008789.html

Короче говоря. Сбой будет только с JDK 1.6_14 (или выше

Я полагаю, вы даже не можете получить jstack или загрузить jconsole?

0 голосов
/ 01 февраля 2012

У нас есть предварительная версия для разработчиков, которая (помимо прочего) устраняет некоторые проблемы с синхронизацией низкого уровня.Если у вас были проблемы с синхронизацией на Mac JDK6, протестируйте этот предварительный просмотр с помощью своего кода и посмотрите, решит ли он проблему на вашем оборудовании.Спасибо.

Предварительный просмотр разработчика в прямом эфире: https://developer.apple.com/downloads/index.action?name=Java%20for%20Mac%20OS%20X%20Developer%20Preview.

0 голосов
/ 27 января 2012

Попробуйте отключить -XX:-UseBiasedLocking Возможно, он пинг-понг, пока код не будет оптимизирован (попробуйте -XX:+PrintCompilation, а затем он эффективно определяет, что программа будет работать быстрее, если только один поток удерживает блокировку. Например, синхронизированный эффективно выходит за пределыloop.

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


Вы можете либо каждый поток альтернативно увеличивать значение, либоВы можете запустить один цикл до остановки (в Integer.MAX_VALUE), а затем второй.

public class CountingWithThreads {
    static long count1 = 0;
    static long count2 = 0;

    public static void main(String... args) throws InterruptedException {
        long start1 = System.nanoTime();
        Thread t1a = new Thread(new CountsSingleThreaded(Integer.MAX_VALUE));
        Thread t1b = new Thread(new CountsSingleThreaded(Integer.MAX_VALUE));
        t1a.start();
        t1b.start();
        t1a.join();
        t1b.join();
        long time1 = System.nanoTime() - start1;
        System.out.printf("Single threaded, took %.1f second to count to %,d%n", time1 / 1e9, count1);

        long start2 = System.nanoTime();
        Thread t2a = new Thread(new CountsAlternatively(true, 1000000));
        Thread t2b = new Thread(new CountsAlternatively(false, 1000000));
        t2a.start();
        t2b.start();
        t2a.join();
        t2b.join();
        long time2 = System.nanoTime() - start2;
        System.out.printf("Alternating multi-threaded took %.1f second to count to %,d%n", time2 / 1e9, count2);

    }

    static class CountsSingleThreaded implements Runnable {
        private final long maxValue;

        CountsSingleThreaded(long maxValue) {
            this.maxValue = maxValue;
        }

        public void run() {
            synchronized (CountingWithThreads.class) {
                for (long i = 0; i < maxValue; i++) {
                    count1++;
                }
            }
        }
    }

    static class CountsAlternatively implements Runnable {
        private final boolean even;
        private final long maximum;

        CountsAlternatively(boolean even, long maximum) {
            this.even = even;
            this.maximum = maximum;
        }

        public void run() {
            try {
                synchronized (CountingWithThreads.class) {
                    while (count2 < maximum)
                        if (((count2 & 1) == 0) == even) {
                            count2++;
                            CountingWithThreads.class.notify();
                        } else {
                            CountingWithThreads.class.wait();
                        }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

печатает

Single threaded, took 2.3 second to count to 4,294,967,294
Alternating multi-threaded took 3.4 second to count to 1,000,000

Запуск одного потока до завершения по одномунаиболее эффективный. Если принудительно чередовать счетчики (самый экстремальный пример многопоточности), это будет более чем в 1000 раз медленнее.

...