在Java中,synchronized关键字和Lock接口(通常通过ReentrantLock实现)都是用来控制并发访问共享资源的机制,但它们在底层实现和特性上有一些不同。下面我们将比较这两种机制的底层原理、可重入性、阻塞性和公平性。
底层原理
-
synchronized
synchronized是Java语言内置的关键字,它的实现由JVM直接支持。当一个线程访问synchronized方法或代码块时,JVM会尝试获取锁。如果锁被其他线程持有,则当前线程会被阻塞,直到锁被释放。synchronized的锁释放和获取通常是通过monitor对象来完成的,monitor对象是与每个对象相关联的。 -
Lock (通过AQS)
Lock接口是Java的一个并发工具,它通常通过AbstractQueuedSynchronizer(AQS)来实现,如ReentrantLock。AQS是一个基于FIFO队列的同步器,它使用了一个内部状态来表示锁是否被持有,以及等待锁的线程队列。当一个线程尝试获取锁时,它会加入这个队列。如果锁被释放,则队列中的线程会被唤醒并尝试获取锁。
可重入性
-
synchronized
synchronized是可重入的,这意味着一个线程可以多次获得同一个锁而不需要再次等待。 -
Lock (通过AQS)
ReentrantLock(基于AQS)也是可重入的。一个线程可以多次获取同一个锁,而不会被阻塞。
阻塞性
-
synchronized
synchronized是阻塞的。如果线程尝试获取已经被其他线程持有的锁,则当前线程会被阻塞,直到锁被释放。 -
Lock (通过AQS)
ReentrantLock(基于AQS)同样是阻塞的。如果锁被其他线程持有,尝试获取锁的线程也会被阻塞,直到锁被释放。但是,Lock接口提供了更灵活的锁获取方式,如tryLock()方法,它允许线程尝试获取锁而不阻塞,如果锁不可用,则立即返回。
公平性
-
synchronized
synchronized的公平性取决于JVM的实现和具体的使用场景。在Java 6及之前,synchronized是非公平的,这意味着等待时间最长的线程不一定会首先获取锁。从Java 7开始,synchronized可以通过JVM参数-XX:UseFairSynchronization来设置为公平的。 -
Lock (通过AQS)
ReentrantLock默认是非公平的,但可以通过构造函数指定为公平的。公平锁保证等待时间最长的线程会首先获取锁。然而,公平锁通常会导致性能下降,因为每次释放锁时都需要检查队列中的线程,以确定哪个线程应该首先获取锁。
总结来说,synchronized和ReentrantLock(基于AQS)在底层实现、可重入性、阻塞性和公平性方面都有相似的特性。但是,Lock接口提供了更多的灵活性和扩展性,而synchronized是Java语言内置的,使用起来更简单,但可能不如Lock接口那么灵活。
本文比较了Java内置的`synchronized`关键字和通过`ReentrantLock`实现的`Lock`接口在并发控制中的差异,涉及底层原理、可重入性、阻塞性和公平性。Lock提供了更多灵活性,而`synchronized`使用更简便。
1005

被折叠的 条评论
为什么被折叠?



