繁体   English   中英

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

[英]Strange concurrency behaviour on Java 6 Mac OS X Lion

我已经尝试了一段时间内在锁和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线程2 ...

此后,Java进程无法接受jvisualvm连接。 CPU负载下降并持续保持在大约1.0%。

Mac OS X Lion 10.7.2(11C74),2.53 GHz英特尔酷睿i5

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

有人可以告诉我这里发生了什么吗?

UPD看起来该错误已在1.6.30中修复, 请参见

您似乎正在观察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(或更高版本的<JDK 7)和Max OS 7上,它才会失败。它们的测试和您看到的结果非常相似。

我猜你甚至不能得到一个jstack或加载jconsole吗?

尝试关闭-XX:-UseBiasedLocking可能会乒乓直到代码被优化为止(尝试-XX:+PrintCompilation ,然后它有效地确定如果只有一个线程持有该锁,则程序将运行得更快,例如,同步已有效地移到了外部循环。

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


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

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

开发人员预览直播: https : //developer.apple.com/downloads/index.action?name=Java%20for%20Mac%20OS%20X%20Developer%20Preview

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM