如果我错了,请随时纠正我!
java中的synced关键字使无法同时在不同线程中运行的方法。在我的程序中,我有4个不同的线程在同一时间运行,总计为100.000。
在将同步关键字添加到要执行的方法时,所花费的时间应该是多线程处理时间的四倍吗?
以任何一种方式执行程序大约需要16秒钟。
这里有我的代码!
public class ExerciseThree {
public static void main(String[] args) {
Even even = new Even();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
System.out.println(even.next());
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
System.out.println(even.next());
}
});
Thread t3 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
System.out.println(even.next());
}
});
Thread t4 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
System.out.println(even.next());
}
});
System.out.println("starting thread 1");
t1.start();
System.out.println("starting thread 2");
t2.start();
System.out.println("starting thread 3");
t3.start();
System.out.println("starting thread 4");
t4.start();
}
}
线程正在调用的方法
public class Even {
private int n = 0;
// public synchronized int next() {
public int next() {
n++;
n++;
return n;
}
}
答案 0 :(得分:1)
println
比计算要昂贵得多,这全都涉及到并发执行。但是,println
本身是同步的,因此无法提高速度。
没有它,只是做
public int next() {
n++;
n++;
return n;
}
受到许多优化。特别是,双精度增量可以用n+=2
代替,并且由于不使用返回值,因此返回值被消除。像
for (int i = 0; i < 100000; i++) {
even.next());
}
可以简化为n += 200000
。
基准标记通常很难,尤其是在Java中。一定要使用JMH,它可以解决大多数问题。
答案 1 :(得分:1)
正如评论部分已经指出的那样,微基准测试是一个复杂的问题,因为许多因素会影响执行时间(例如,即时编译和垃圾回收)。评论部分已经提供了不错的reference,但我建议您也看看我的answer,以了解类似的问题,该问题由external resource链接到Peter Sestoft可以很好地介绍微基准测试以及需要注意的内容。
已经提到println()
在这样的微基准测试中没有位置。此外,我想指出您应该使用某种同步机制(例如CountDownLatch
)来确保四个线程同时开始执行其工作。创建和启动线程所涉及的开销可能导致较早的线程在较晚的线程开始工作的过程中抢占先机,从而导致even
锁的争用少于预期。例如,可能看起来像这样:
public class ExerciseThree {
public static void main(String[] args) {
final CountDownLatch startSignal = new CountDownLatch(1);
final CountDownLatch threadReadyCheck = new CountDownLatch(4);
final CountDownLatch threadDoneCheck = new CountDownLatch(4);
Even even = new Even();
Thread t1 = new Thread(() -> {
threadReadyCheck.countDown();
startSignal.await();
for (int i = 0; i < 100000; i++) {
even.next();
}
threadDoneCheck.countDown();
});
Thread t2 = new Thread(() -> {
threadReadyCheck.countDown();
startSignal.await();
for (int i = 0; i < 100000; i++) {
even.next();
}
threadDoneCheck.countDown();
});
Thread t3 = new Thread(() -> {
threadReadyCheck.countDown();
startSignal.await();
for (int i = 0; i < 100000; i++) {
even.next();
}
threadDoneCheck.countDown();
});
Thread t4 = new Thread(() -> {
threadReadyCheck.countDown();
startSignal.await();
for (int i = 0; i < 100000; i++) {
even.next();
}
threadDoneCheck.countDown();
});
t1.start();
t2.start();
t3.start();
t4.start();
// Wait until all threads are ready to perform their work.
threadReadyCheck.await();
// All threads ready.
// This is where you log start time.
long start = System.nanoTime();
// Let threads progress to perform their actual work.
startSignal.countDown();
// Wait for threads to finish their work.
threadDoneCheck.await();
long end = System.nanoTime();
// Note that this is again subject to many factors, for example when the main thread gets scheduled again after the workers terminate.
long executionTime = end - start;
}
}