MK *_*ung 6 java multithreading jvm locking
我知道这synchronize(LOCK)是不公平的,这意味着不能保证等待时间最长的线程会赢得锁。然而,在我下面的小实验中,似乎锁是由最短的等待线程获取的......
public class Demo {
public static final Object LOCK = new Object();
public void unfairDemo(){
// Occupy the lock for 2 sec
new Thread(() -> {
synchronized (LOCK) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// Spawn 10 new threads, each with 100ms interval, to see which can win the lock
// If lock is fair then it should print the i in asc order
for (var i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
System.out.println("Added " + String.valueOf(finalI) + "th element to wait for lock");
synchronized (LOCK) {
System.out.println("I got the lock, says " + String.valueOf(finalI) + "-th thread");
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
// Keep the program alive
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行不公平演示()打印以下内容:
Added 0th element to wait for lock
Added 1th element to wait for lock
Added 2th element to wait for lock
Added 3th element to wait for lock
Added 4th element to wait for lock
Added 5th element to wait for lock
Added 6th element to wait for lock
Added 7th element to wait for lock
Added 8th element to wait for lock
Added 9th element to wait for lock
I got the lock, says 9-th thread
I got the lock, says 8-th thread
I got the lock, says 7-th thread
I got the lock, says 6-th thread
I got the lock, says 5-th thread
I got the lock, says 4-th thread
I got the lock, says 3-th thread
I got the lock, says 2-th thread
I got the lock, says 1-th thread
I got the lock, says 0-th thread
Run Code Online (Sandbox Code Playgroud)
我预计顺序会被打乱,但无论我如何尝试,结果都是相反的。我在这里做错了什么?
有许多来源,例如this,已经表明不应假设线程获取锁的顺序。但这并不意味着必须打乱订单。
它可能至少取决于 JVM 实现。例如,这个关于 HotSpot 的文档说:
争用同步操作使用先进的自适应旋转技术来提高吞吐量,即使对于具有大量锁争用的应用程序也是如此。因此,同步性能变得如此之快,以至于对于绝大多数现实世界的程序来说,这不是一个重要的性能问题。
...
在没有争用的正常情况下,同步操作将完全在快速路径中完成。但是,如果我们需要阻塞或唤醒线程(分别在 monitorenter 或 monitorexit 中),快速路径代码将调用慢速路径。慢路径实现是在本机 C++ 代码中实现的,而快速路径是由 JIT 发出的。
我不是 HotSpot 的专家(也许其他人可以提供更权威的答案),但基于C++ 代码,看起来竞争线程将被推送到 LIFO 结构上,这可能解释了您的类似堆栈的顺序观察到的:
Run Code Online (Sandbox Code Playgroud)// * Contending threads "push" themselves onto the cxq with CAS // and then spin/park. ... // Cxq points to the set of Recently Arrived Threads attempting entry. // Because we push threads onto _cxq with CAS, the RATs must take the form of // a singly-linked LIFO.