【发布时间】:2021-09-23 01:54:57
【问题描述】:
我正在阅读 Java 中的多线程和使用同步块。假设我有两个不同的、独立的同步块。我可以让它们并行运行,方法是为两个同步块分别使用一个锁。但是如果我对两个同步块使用相同的锁,我认为只有一个可以在给定时间运行。 我这样想错了吗?如果不是,为什么我会得到以下奇怪的结果?
假设我有两个独立的操作,increment1 和 increment2,分别由不同的线程调用。
public class AppMultipleSynchronization {
private static int counter1 = 0;
private static int counter2 = 0;
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void increment1() {
synchronized (lock1) {
counter1++;
}
}
public static void increment2() {
synchronized (lock2) {
counter2++;
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000000; i++) {
increment1();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000000; i++) {
increment2();
}
}
});
long startTime = System.currentTimeMillis();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("total time taken: " + (endTime - startTime) + "ms");
System.out.println("counter1: " + counter1 + "\ncounter2: " + counter2);
}
}
如您所见,我对两个增量都使用了不同的锁。
要使用相同的锁,请使用完全相同的程序,在两种情况下都替换为lock1。
两个锁时的输出:
total time taken: 13437ms
counter1: 100000000
counter2: 100000000
单锁情况下的输出:
total time taken: 5139ms
counter1: 100000000
counter2: 100000000
【问题讨论】:
-
您有多少个处理器?尝试找出所花费的时间,而不是 synchronized(AppMultipleSynchronization.class) 使用 synchronized(lock1)
-
使用 JMH,假设我设置正确,我看不到平均执行时间有如此显着的差异:一个锁,
487.514 ± 22.413 ms/op;两把锁,1064.114 ± 24.043 ms/op。执行时间只增加了半秒多一点。注意我循环了一千万次而不是一亿次。 -
@Gunwant 我试过 lock1 而不是 AppMultipleSynchronization.class..但结果还是一样...
-
有太多的因素需要通过实验来弄清楚......首先,您要在非最终字段上进行同步。尽管关于 final 对同步块的作用的描述只提到了安全性并且您没有更改值,但在我的测试中添加 final 将时间减少了一半。其次,必须进行一些大的优化——如果我将 main 方法的代码放在一个循环中,不同迭代所花费的时间非常不一致,有时会长 10 倍。第三,对我来说,在本地使用两个锁的方法比在 lock1 上都快。
-
几乎每次出现“Java 的性能不如我预期”这样的问题时,正确答案都是your benchmark is wrong。用 Java 编写正确的微基准测试很难,如果您至少不为此使用现有工具/库,那么您没有考虑所有可能的陷阱的可能性非常高。
标签: java multithreading locking