簡體   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