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