侧边栏壁纸
博主头像
Dioxide-CN博主等级

茶边话旧,看几许星迢露冕,从淮海南来。

  • 累计撰写 54 篇文章
  • 累计创建 30 个标签
  • 累计收到 24 条评论

目 录CONTENT

文章目录

JUC核心之AQS

Dioxide-CN
2023-01-09 / 0 评论 / 2 点赞 / 28 阅读 / 823 字
温馨提示:
本文最后更新于 2023-01-09,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

JUC核心之AQS

重入锁ReentrantLock的初步认识

什么是锁

锁是用来解决多线程并发访问共享资源所带来的的数据安全性问题的手段。对一个共享资源加锁后,如果有一个线程获得了锁,那么其他线程无法访问这个共享资源。

加锁前后的区别

image-1673251173337

什么是重入锁

一个持有锁的线程再释放锁之前,如果再次访问了该同步锁的其他方法,这个线程不需要再次争抢锁,只需要记录重入的次数。

public class Main {  
    static Lock lock = new ReentrantLock(); // 重入锁  
    static int count = 0;  
    static void incr() { // 递增  
        lock.lock();  
        count++;  
        /*  
         * 但是这是重入锁 线程A 已经获得了该重入锁 调用方法内  
         * 再次请求增强锁不会导致死锁 只会记录重入的次数  
         * 所以重入锁可以解决死锁的问题  
         */        decr();  
        lock.unlock();  
    }  
	  
    static void decr() { // 递减  
        /* 又需要增强锁 线程A 要等 线程A 释放锁,发生死锁 */        lock.lock();  
        count--;  
        lock.unlock();  
    }  
	  
    public static void main(String[] args) throws InterruptedException {  
        for (int i = 0; i < 1000; i++) {  
            new Thread(Main::incr).start();  
        }  
        Thread.sleep(3000);  
        System.out.println("result : " + count);  
    }  
}

锁的类图

image-1673251198642

AQS是什么

问题思考:锁是如何实现线程的阻塞以及唤醒的?互斥的逻辑是怎么实现的?

ReentrantLock的类关系图

image-1673251212590

lock.lock()源码

// jdk 17
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
	@ReservedStackAccess  
	final void lock() {
	    if (!initialTryLock())  
	        acquire(1);  
	}
}
// 非公平锁
static final class NonfairSync extends Sync {
	final boolean initialTryLock() {  
	    Thread current = Thread.currentThread();
	    // CAS 操作修改 state (互斥变量 0 表示无锁 > 0 表示有锁)
	    // 本质是乐观锁 预期值为 0 时修改为 1
	    if (compareAndSetState(0, 1)) {
		    // 设置当前线程为独占状态
	        setExclusiveOwnerThread(current);
	        return true;
	    } else if (getExclusiveOwnerThread() == current) {
	        int c = getState() + 1;
	        if (c < 0) // overflow
	            throw new Error("Maximum lock count exceeded");
	        setState(c);
	        return true;
	    } else
	        return false;
	}
	// 尝试抢占锁
	protected final boolean tryAcquire(int acquires) {
		// 判断 state 占用状态和 CAS 结果
	    if (getState() == 0 && compareAndSetState(0, acquires)) {  
		    // 设置当前线程为独占状态
	        setExclusiveOwnerThread(Thread.currentThread());  
	        return true;  
	    }  
	    return false;  
	}
}
// 公平锁
static final class FairSync extends Sync {...}

public ReentrantLock() {
	// 构造的时候默认构造了一个非公平锁
    sync = new NonfairSync();  
}

public void lock() {
	// lock.lock()
    sync.lock();
}

public final void acquire(int arg) {
	// 尝试抢占锁 arg 抢占的数量
    if (!tryAcquire(arg))
	    // AQS
        acquire(null, arg, false, false, false, 0L);  
}

initialTryLock() 方法在公平锁和非公平锁中均有实现,公平锁意味着已经获得了锁的线程释放了锁那么应该从等待的线程中去唤醒一个线程去访问,非公平锁意味着在等待的线程中突然出现了一个新的线程来抢占锁是有可能被抢占走的。

lock.unlock()源码

abstract static class Sync extends AbstractQueuedSynchronizer {
	@ReservedStackAccess  
	protected final boolean tryRelease(int releases) {
	    int c = getState() - releases;
	    if (getExclusiveOwnerThread() != Thread.currentThread())  
	        throw new IllegalMonitorStateException();  
	    boolean free = (c == 0); // 表示可以释放锁
	    if (free)
		    // 设置为 null 后完成锁的释放
	        setExclusiveOwnerThread(null);  
	    setState(c);  
	    return free;  
	}
}

public void unlock() {  
    sync.release(1);  
}

public final boolean release(int arg) {  
    if (tryRelease(arg)) {  
        signalNext(head);  
        return true;  
    }  
    return false;  
}

private static void signalNext(Node h) {  
    Node s;
    // 这里通过 GC 回收
    if (h != null && (s = h.next) != null && s.status != 0) {  
        s.getAndUnsetStatus(WAITING);
        // 在这里完成锁的释放
        LockSupport.unpark(s.waiter);
    }  
}

原理运行图

image-1673251244825

2

评论区