[英]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.