返回

剖析AQS源码(三):探秘共享锁的获取与释放

Android

在深入理解AQS锁的获取与释放机制之前,我们已经对独占锁进行了详细的剖析。本篇将继续探究AQS共享锁的获取与释放过程,为我们全面掌握AQS锁机制奠定基础。

共享锁与独占锁的异同

尽管共享锁与独占锁在AQS的实现框架中颇为相似,但它们仍存在着一些关键差异:

  • 排他性: 独占锁不允许其他线程同时获取锁,而共享锁则允许多个线程同时持有锁。
  • 竞争策略: 在竞争独占锁时,线程会独占地尝试获取锁,而共享锁则采取非独占的方式,即多个线程可以并行地尝试获取锁。
  • 公平性: 独占锁通常采用公平锁策略,保证线程获取锁的顺序与请求顺序一致,而共享锁则通常采用非公平锁策略,允许线程以非先来后到的方式获取锁。

获取共享锁

获取共享锁的流程与独占锁类似,主要分为以下几个步骤:

1. 自旋获取: 线程首先尝试自旋获取锁,即不断检查锁的状态是否为无锁状态。如果锁是无锁的,则线程直接获取锁并返回。

2. 排队等待: 如果自旋获取失败,则线程会进入等待队列。在等待队列中,线程会轮询锁的状态,直到锁被释放。

3. 获取锁: 当锁被释放时,等待队列中的一个线程将被唤醒并尝试获取锁。如果线程成功获取锁,则返回并执行临界区代码,否则回到步骤2继续等待。

释放共享锁

释放共享锁的过程也与独占锁类似,主要分为以下几个步骤:

1. 验证锁状态: 线程首先验证它是否持有锁,即检查锁的持有线程是否与当前线程一致。

2. 减少持有计数: 如果线程持有锁,则减少锁的持有计数。如果持有计数降为0,则表示没有线程持有锁,锁被释放。

3. 唤醒等待线程: 如果锁被释放,则唤醒等待队列中所有等待的线程。这些线程将再次尝试获取锁。

实例解析

为了更深入地理解共享锁的获取与释放过程,我们以示例代码为例进行解析:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SharedLockDemo {

    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                lock.readLock().lock();
                System.out.println(Thread.currentThread().getName() + " 获取共享锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.readLock().unlock();
                    System.out.println(Thread.currentThread().getName() + " 释放共享锁");
                }
            });
        }
        for (Thread thread : threads) {
            thread.start();
        }
    }
}

在这个示例中,我们创建了10个线程并使用ReentrantReadWriteLock实现了共享锁。每个线程尝试获取共享锁,执行临界区代码(在示例中为打印信息),然后释放锁。输出如下所示:

Thread-0 获取共享锁
Thread-1 获取共享锁
Thread-2 获取共享锁
Thread-3 获取共享锁
Thread-4 获取共享锁
Thread-5 获取共享锁
Thread-6 获取共享锁
Thread-7 获取共享锁
Thread-8 获取共享锁
Thread-9 获取共享锁
Thread-0 释放共享锁
Thread-1 释放共享锁
Thread-2 释放共享锁
Thread-3 释放共享锁
Thread-4 释放共享锁
Thread-5 释放共享锁
Thread-6 释放共享锁
Thread-7 释放共享锁
Thread-8 释放共享锁
Thread-9 释放共享锁

从输出中可以看出,多个线程同时持有共享锁,这印证了共享锁的非独占性。线程以非先来后到的顺序获取和释放锁,这表明共享锁采用了非公平策略。

总结

通过剖析AQS共享锁的获取与释放过程,我们深入了解了共享锁的非独占性和非公平性特点。通过实例解析,我们也直观地观察到了共享锁的实际应用。对AQS锁机制的深入理解有助于我们在实际项目中高效地使用锁,保证并发程序的正确性和性能。