如果我错了,请随时纠正我!
java中的synchronized关键字使得一个方法不能同时在不同的线程上运行。在我的程序中,我有4个不同的线程在同一时间运行,数到100.000。
当将synchronized关键字添加到正在执行的方法时,它所需的时间应该是多线程的四倍?
以任何一种方式执行程序,大约需要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;
}
}
发布于 2018-08-21 06:43:17
正如在评论部分中已经指出的,微基准测试是一个复杂的问题,因为许多因素会影响执行时间(例如,即时编译和垃圾收集)。评论部分已经提供了一个很好的reference,但我建议您还可以查看我的answer中类似的问题,该问题链接到Peter Sestoft的external resource,它提供了对微基准测试的非常好的介绍以及需要注意的内容。
前面已经提到,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;
}
}
发布于 2018-08-21 06:40:52
由于println
比计算成本高得多,所以都是关于计算的并发执行。但是,println
本身是同步的,因此不能提高速度。
没有它,只做
public int next() {
n++;
n++;
return n;
}
需要进行许多优化。特别是双倍递增可以被n+=2
替换,并且由于返回值不被使用,返回值被消除。像这样的循环
for (int i = 0; i < 100000; i++) {
even.next());
}
可以减少到只有n += 200000
。
基准测试通常很难,尤其是在Java中。一定要使用JMH,它可以解决大多数问题。
https://stackoverflow.com/questions/51937035
复制相似问题