章
目
录
Java面试题:谈谈Java中常用的锁及其原理?
得分点:
对象头、AQS
标准回答:
在Java中,有两种主要的加锁方式,分别是使用synchronized
关键字和Lock
接口。Lock
接口的经典实现是ReentrantLock
,而另一个接口ReadWriteLock
的经典实现是ReentrantReadWriteLock
。这两种方式的底层实现依赖于不同的机制。
synchronized关键字
synchronized
的底层实现依赖于Java对象头(Object Header)。Java对象头包含三部分信息:Mark Word(标记字)、Class Metadata Address(类元数据地址)、Array length(数组长度)。Mark Word用于存储对象的hashCode和锁信息,Class Metadata Address存储对象类型的指针,而Array length用于存储数组对象的长度。
Lock接口和AQS(AbstractQueuedSynchronizer)
Lock
接口的实现通常依赖于AQS,AQS是一个队列同步器,用于构建锁的基础框架。Lock
接口的实现类都是基于AQS实现的。AQS采用了模板方法模式的设计,锁的实现需要继承AQS并重写指定的方法。AQS内部定义了一个FIFO(先进先出)的队列来实现线程的同步,同时还定义了同步状态来记录锁的信息。
加分回答:
ReentrantLock
通过内部类Sync
定义了锁的行为,同时它还定义了Sync
的两个子类,FairSync
和NonfairSync
,这两个子类分别代表公平锁和非公平锁。Sync
继承自AQS,它不仅使用AQS的同步状态来记录锁的信息,还利用同步状态记录了重入次数。同步状态是一个整数,当它为0时代表无锁,当它为N时则代表线程持有锁并重入了N次。
ReentrantReadWriteLock
也支持重入的方式,与ReentrantLock
一致,它同样定义了内部类Sync
,并定义了两个子类FairSync
和NonfairSync
,来实现公平锁和非公平锁。另外,ReentrantReadWriteLock
内部包含了读锁和写锁两种锁,这两种锁都是由Sync
来实现的。区别在于读锁支持共享,即多个线程可以同时获得读锁,而写锁是互斥的,只允许一个线程获得写锁。这种设计允许多个线程同时读取共享资源,但只允许一个线程进行写操作,以提高并发性能。