设为首页 加入收藏

TOP

万字长文硬核AQS源码分析(一)
2023-08-26 21:10:29 】 浏览:128
Tags:文硬核 AQS

阅读本文前,需要储备的知识点如下,点击链接直接跳转。
java线程详解
Java不能操作内存?Unsafe了解一下
一文读懂LockSupport

AQS简介

AQS即AbstractQueuedSynchronizer的简称,翻译过来就是抽象队列同步器的意思,由Doug Lea大神开发的。说他抽象是因为它提供的是一个基于队列的同步器框架,定义了一些基础功能方法(控制状态变量,获取和释放同步状态方法以及入队出队操作等),具体场景使用只需要根据需要实现对应的方法即可。我们在锁(比如ReentrantLock)、并发工具类(比如CountDownLatch)都可以看到内部类继承了AbstractQueuedSynchronizer,也就是说AQS才是这些类的基石。说了这么多,感觉把抽象说的越抽象了,下面我们从几个栗子入手吧。

注意:本文使用的JDK版本为JDK8,AQS的代码非常巧妙和经典,很多细节和模块都可以单独拉出来写一篇文章,很多细节问题建议自行阅读和思考。
本篇文章主要讲独占模式的应用和原理分析,关于共享模式不再这里展开细讲。

应用举例

ReentrantLock的使用

3个线程获取同一个锁,获得后休眠1秒结束,所以3个线程间隔1秒打印输出。

public class ReentrantLockTest {
    public static void main(String[] args) {
        lockTest();
    }

    public static void lockTest() {
        ReentrantLock lock = new ReentrantLock();
        PrintThread t1 = new PrintThread(lock, "t1");
        PrintThread t2 = new PrintThread(lock, "t2");
        PrintThread t3 = new PrintThread(lock, "t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

class PrintThread extends Thread {
    private Lock lock;

    public PrintThread(Lock lock, String threadName) {
        this.lock = lock;
        this.setName(threadName);
    }

    @Override
    public void run() {
        lock.lock();
        try {
            System.out.println(String.format("time:%s,thread:%s,result:%s",
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()),
                Thread.currentThread().getName(), "get lock success"));
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

打印结果如下

time:2021-04-13 13:53:55,thread:t1,result:get lock success
time:2021-04-13 13:53:56,thread:t2,result:get lock success
time:2021-04-13 13:53:57,thread:t3,result:get lock success

是因为这3个线程执行时都要先获取锁执行完逻辑后再释放锁,而ReentrantLock独占锁,相当于这3个线程间是串行执行的,相互间隔1秒(注意,线程的先后执行顺序不一定是固定的,但线程内有休眠1秒的操作,所以至少相隔1秒)

CountDownLatch的使用

main线程创建一个CountDownLatch latch = new CountDownLatch(1),3个线程持有该CountDownLatch并调用CountDownLatchawait()方法,直到main线程休眠2秒后执行CountDownLatchcountDown()方法,释放一个同步状态使得数量值为0,唤醒等待在await()的线程继续执行。

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        ConcurrentThread concurrentThread1 = new ConcurrentThread(latch, "t1");
        ConcurrentThread concurrentThread2 = new ConcurrentThread(latch, "t2");
        ConcurrentThread concurrentThread3 = new ConcurrentThread(latch, "t3");
        concurrentThread1.start();
        concurrentThread2.start();
        concurrentThread3.start();
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + " countDown...");
        latch.countDown();
    }
}

class ConcurrentThread extends Thread {

    private CountDownLatch latch;

    public ConcurrentThread(CountDownLatch latch, String threadName) {
        this.latch = latch;
        this.setName(threadName);
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is ready...");
        try {
            latch.await();
            System.out.println(Thread.currentThread().getName() + " is executing...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

打印结果如下(注意,线程的先后执行顺序不一定是固定的)

t1 is ready...
t3 is ready...
t2 is ready...
main countDown...
t1 is executing...
t3 is executing...
t2 is execut
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/10/10
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇《深入理解Java虚拟机》读书笔记.. 下一篇Spring Boot + Spring Batch 实现..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目