大家好,我是欧阳方超,公众号同名。
1 概述
在Java编程中,synchronized关键字是实现线程安全的重要工具。然而,它的公平性问题常常引发讨论。本文将深入探讨Synchronized为何被视为非公平锁,以及这一特性对多线程编程的影响。
2 什么是非公平锁
非公平锁是指在多个线程争用同一把锁时,锁的获取顺序不遵循请求的顺序。当一个线程释放锁时,JVM并不保证等待队列中的线程会按照它们的等待顺序来获取锁。相反,新的或正在等待的线程可以直接尝试获取锁,这种设计旨在提高系统的吞吐量和效率。
3 Synchronized的设计初衷
Synchronized的设计目标主要是为了实现线程之间的同步,而非严格的公平性。其工作机制基于对象监视器(monitor),每个对象都有一个与之关联的监视器。当一个线程需要获取某个对象的锁时,它会首先尝试获取该对象关联的监视器。如果监视器被其他线程占用,该线程将进入等待队列。
3.1 效率优先
减少上下文切换:非公平锁允许新来的线程直接尝试获取锁,这样可以减少线程切换带来的开销,从而提升性能。
避免饥饿现象:尽管非公平锁可能导致某些线程等待时间变长,但在实际应用中,由于线程调度的不确定性,长时间无法获取锁(即饥饿现象)的情况较少发生。
3.2 非公平锁的特点
性能优势:由于减少了上下文切换的开销,非公平锁通常具有更好的性能表现。
潜在饥饿问题:虽然在大多数情况下不会出现,但在特定场景下,某些线程可能会长时间无法获得锁,这种现象称为饥饿
4 如何实现公平锁
如果需要更严格的公平性,可以使用ReentrantLock类。与synchronized不同,ReentrantLock允许开发者通过构造函数指定是否为公平锁。当设置为公平锁时,它会按照等待队列中线程请求的顺序来分配锁,从而实现更高程度的公平性。
Lock fairLock = new ReentrantLock(true); // 创建一个公平锁
4.1 公平锁的特点与使用场景
特点
顺序获取:线程按照请求锁的顺序依次获取锁。
避免饥饿:确保每个线程都有机会获取锁,避免长时间等待。
使用场景
任务调度:需要确保任务按照特定顺序执行。
资源分配:需要公平地分配有限资源。
5 总结
synchronized作为Java中的内置同步机制,其默认实现为非公平锁。这一设计基于性能考虑和避免饥饿现象,是多线程编程中的一种折中方案。在大多数场景下,其性能优势足以弥补不公平性带来的潜在问题。然而,在需要严格控制执行顺序和资源分配的场合,使用ReentrantLock等其他工具可能更为合适。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。