我一直在试验内在锁和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 ...
之后,java进程无法接受jvisualvm
连接。 CPU负载下降并持续保持在1.0%左右。
Mac OS X Lion 10.7.2(11C74),2.53 GHz Intel Core i5
java版“1.6.0_29”Java(TM)SE运行时环境(构建 1.6.0_29-b11-402-11M3527)Java HotSpot(TM)64位服务器VM(版本20.4-b02-402,混合模式)
有人能告诉我这里到底发生了什么事吗?
UPD 看起来该错误将在1.6.30 see
中修复答案 0 :(得分:1)
看起来您正在观察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(或更高 我猜你甚至无法获得jstack或加载jconsole?
答案 1 :(得分:0)
尝试关闭-XX:-UseBiasedLocking
它可能是ping-pongs直到代码优化(尝试-XX:+PrintCompilation
然后它有效地确定如果只有一个线程持有锁,程序将运行得更快。例如,synchronized有效地移出了循环。
当您使用多个线程执行单线程更快的操作时,您将经常看到此行为。
你可以让每个线程交替增加值,也可以让一个循环运行直到它停止(在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倍。
答案 2 :(得分:0)
我们有一个开发人员预览(除其他外)修复了一些低级同步问题。如果您在Mac JDK6上遇到同步问题,请使用您的代码测试此预览,看看它是否能解决您硬件上的问题。感谢。