简体   繁体   English

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

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

I've been experimenting with difference between intrinsic locks and java.util.concurrent.ReentrantLock for some time now. 我已经尝试了一段时间内在锁和java.util.concurrent.ReentrantLock之间的区别。 I've found very strange thing. 我发现很奇怪的事情。 Consider following code: 考虑以下代码:

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++;
    }
}

Simple thing, no fancy stuff. 简单的事情,没有花哨的东西。 Right? 对? Happens to break! 发生故障! Most likely when you run it, it won't end. 当您运行它时,它很可能不会结束。 After some ping-pong between threads you'll see only one thread is actually running. 在线程之间进行一些乒乓球之后,您将看到实际上只有一个线程在运行。 The other hangs forever: 另一个永远

Thread-1 Thread-2 Thread-1 Thread-2 Thread-1 ... Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 ... 线程1线程2线程1线程2线程1 ...线程2线程2线程2线程2线程2线程2线程2线程2线程2线程2 ...

After that, java process can't accept jvisualvm connection. 此后,Java进程无法接受jvisualvm连接。 CPU load drops and continuously stays at about 1.0%. CPU负载下降并持续保持在大约1.0%。

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

java version "1.6.0_29" Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11M3527) Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode) Java版本“ 1.6.0_29” Java SE运行时环境(内部版本1.6.0_29-b11-402-11M3527)Java HotSpot™64位服务器VM(内部版本20.4-b02-402,混合模式)

Can someone tell me what the heck is happening here? 有人可以告诉我这里发生了什么吗?

UPD Looks like the bug will be fixed in 1.6.30 see UPD看起来该错误已在1.6.30中修复, 请参见

Looks like you are observing an existing bug in Mac OS 7 JDK 1.6. 您似乎正在观察Mac OS 7 JDK 1.6中的一个现有错误。 You can see the same issue occurred here: 您可以在此处看到相同的问题:

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

You may want to read from the start at 您可能想从头开始阅读

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

Finally there seems to be a resolution in for Open JDK 7. 最终,Open JDK 7似乎有了解决方案。

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

Long story short. 长话短说。 It will only fail with JDK 1.6_14 (or greater < JDK 7) and Max OS 7. Their test and the results you are seeing are very similar. 只有在JDK 1.6_14(或更高版本的<JDK 7)和Max OS 7上,它才会失败。它们的测试和您看到的结果非常相似。

I am guessing you can't even get a jstack or load jconsole? 我猜你甚至不能得到一个jstack或加载jconsole吗?

Try turning off -XX:-UseBiasedLocking It probably ping-pongs until the code is optimised (try -XX:+PrintCompilation and then it effectively determines the program will run faster if only one thread holds the lock. eg the synchronized is effectively moved outside the loop. 尝试关闭-XX:-UseBiasedLocking可能会乒乓直到代码被优化为止(尝试-XX:+PrintCompilation ,然后它有效地确定如果只有一个线程持有该锁,则程序将运行得更快,例如,同步已有效地移到了外部循环。

You will see this behaviour often when you using multiple threads to do something which is faster to do single threaded. 当您使用多线程来执行比单线程更快的操作时,您经常会看到此行为。


You can either have each thread alternatively increment the value or you can have one loop run until it stops (at Integer.MAX_VALUE) and then the second one. 您可以让每个线程交替增加该值,也可以运行一个循环直到其停止(在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();
            }
        }
    }
}

prints 版画

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

Running one thread to completion one at a time is the most efficient. 一次运行一个线程来完成一个线程是最有效的。 If you force strict alternating of the counters (the most extreme example of mult-threading) it is over 1000x slower. 如果您强制计数器的严格轮换(多线程的最极端示例),则速度要慢1000倍以上。

We have a developer preview that (among other things) fixes some low level synchronization problems. 我们有一个开发人员预览版,(除其他功能外)修复了一些底层同步问题。 If you've had problems with synchronization on Mac JDK6, please test this preview with your code and see if it fixes the problem on your hardware. 如果您在Mac JDK6上的同步遇到问题,请使用您的代码测试此预览,并查看它是否可以解决您的硬件问题。 Thanks. 谢谢。

The developer preview is live: https://developer.apple.com/downloads/index.action?name=Java%20for%20Mac%20OS%20X%20Developer%20Preview . 开发人员预览直播: 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