在多线程环境中,公平锁保证了等待获取锁的线程按照请求锁的顺序来获取锁。也就是说,先请求锁的线程会先获得锁。
非公平锁则不保证等待获取锁的线程的执行顺序。这意味着即使某个线程最早请求锁,也可能会在其他后来请求锁的线程之后获得锁。非公平锁可能会导致“饥饿”问题,但通常具有更高的吞吐量。
synchronized 并没有明确规定锁的公平性,但在实际行为上来看,它是一种非公平锁。
主要是因为JVM在管理等待锁的线程时,并不遵循先来先服务的原则。在多线程环境下,当多个线程尝试进入由 synchronized 保护的同步块或方法时,JVM 和操作系统的调度器并不保证哪个线程会首先获得锁。这意味着一个刚刚请求锁的线程可能会在已经等待较长时间的线程之前获得锁。
这样的设计主要是出于性能考虑。非公平锁通常比公平锁具有更高的吞吐量,因为维护一个等待队列并确保线程按顺序获得锁会增加额外的开销。在大多数情况下,非公平锁能够提供更好的性能,而且简化了锁的实现。
尽管 synchronized 的这种非公平性可能导致某些线程饥饿(即永远获取不到锁),但在实际应用中,由于大多数锁持有时间较短,这种情况出现的频率并不高。此外,JVM 的锁优化机制(如偏向锁、轻量级锁和锁膨胀)以及操作系统层面的线程调度策略也有助于减少饥饿问题的发生。