直接上代码:
public class MyLockBaseOnAqs { // 定义一个同步器,实现AQS类 private static class Sync extends AbstractQueuedSynchronizer { // 实现tryAcquire(acquires)方法 @Override public boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // 实现tryRelease(releases)方法 @Override protected boolean tryRelease(int releases) { setExclusiveOwnerThread(null); setState(0); return true; } } // 声明同步器 private final Sync sync = new Sync(); // 加锁 public void lock() { sync.acquire(1); } // 解锁 public void unlock() { sync.release(1); } private static int count = 0; public static void main(String[] args) throws InterruptedException { MyLockBaseOnAqs lock = new MyLockBaseOnAqs(); CountDownLatch countDownLatch = new CountDownLatch(1000); IntStream.range(0, 1000).forEach(i -> new Thread(() -> { lock.lock(); try { IntStream.range(0, 10000).forEach(j -> { count++; }); } finally { lock.unlock(); } // System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); }, "tt-" + i).start()); countDownLatch.await(); System.out.println(count); } }运行main()方法总是打印出10000000(一千万),说明这个锁也是可以直接使用的,当然这也是一个不可重入的锁。
是不是很简单,只需要简单地实现AQS的两个方法就完成了上一章彤哥自己动手实现的锁的功能。
它是怎么实现的呢?
我们这一章先不讲源码,后面学习了ReentrantLock自然就明白了。
总结这一章就到此结束了,本篇没有去深入的解析AQS的源码,笔者认为这没有必要,因为对于从来都没有看过锁相关的源码的同学来说,一上来就讲AQS的源码肯定会一脸懵逼的,具体的源码我们穿插在后面的锁和同步器的部分来学习,等所有跟AQS相关的源码学习完毕了,再来一篇总结。
下面总结一下这一章的主要内容:
(1)AQS是Java中几乎所有锁和同步器的一个基础框架,这里说的是“几乎”,因为有极个别确实没有通过AQS来实现;
(2)AQS中维护了一个队列,这个队列使用双链表实现,用于保存等待锁排队的线程;
(3)AQS中维护了一个状态变量,控制这个状态变量就可以实现加锁解锁操作了;
(4)基于AQS自己动手写一个锁非常简单,只需要实现AQS的几个方法即可。
彩蛋上一章彤哥自己动手写的锁,其实可以看成是AQS的一个缩影,看懂了那个基本上AQS可以看懂一半了,因为彤哥那个里面没有写Condition相关的内容,下一章ReentrantLock重入锁中我们将一起学习Condition相关的内容。
所以呢,还是建议大家去看看这篇文章,点击下面的推荐阅读可以直达。
推荐阅读死磕 java同步系列之自己动手写一个锁Lock
死磕 java魔法类之Unsafe解析
死磕 java同步系列之JMM(Java Memory Model)
死磕 java同步系列之volatile解析
死磕 java同步系列之synchronized解析
欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一起畅游源码的海洋。