Java 6 Mac OS X Lion上的奇怪并发行为

时间:2012-01-27 18:23:33

标签: java multithreading macos osx-lion synchronized

我一直在试验内在锁和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螺纹-1 ...螺纹-2螺纹-2   螺纹-2螺纹-2螺纹-2螺纹-2螺纹-2螺纹-2螺纹-2 ...

之后,java进程无法接受jvisualvm连接。 CPU负载下降并持续保持在1.0%左右。

  

Mac OS X Lion 10.7.2(11C74),2.53 GHz Intel Core i5

     

java版“1.6.0_29”Java(TM)SE运行时环境(构建   1.6.0_29-b11-402-11M3527)Java HotSpot(TM)64位服务器VM(版本20.4-b02-402,混合模式)

有人能告诉我这里到底发生了什么事吗?

UPD 看起来该错误将在1.6.30 see

中修复

3 个答案:

答案 0 :(得分:1)

看起来您正在观察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?

答案 1 :(得分:0)

尝试关闭-XX:-UseBiasedLocking它可能是ping-pongs直到代码优化(尝试-XX:+PrintCompilation然后它有效地确定如果只有一个线程持有锁,程序将运行得更快。例如,synchronized有效地移出了循环。

当您使用多个线程执行单线程更快的操作时,您将经常看到此行为。


你可以让每个线程交替增加值,也可以让一个循环运行直到它停止(在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倍。

答案 2 :(得分:0)

我们有一个开发人员预览(除其他外)修复了一些低级同步问题。如果您在Mac JDK6上遇到同步问题,请使用您的代码测试此预览,看看它是否能解决您硬件上的问题。感谢。

开发者预览是实时的:https://developer.apple.com/downloads/index.action?name=Java%20for%20Mac%20OS%20X%20Developer%20Preview