前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JUC核心之AQS

JUC核心之AQS

作者头像
DioxideCN
发布2023-01-10 10:04:53
2280
发布2023-01-10 10:04:53
举报

JUC核心之AQS

重入锁ReentrantLock的初步认识

什么是锁

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

加锁前后的区别

image-1673251173337
image-1673251173337

什么是重入锁

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

代码语言:javascript
复制
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
image-1673251198642

AQS是什么

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

ReentrantLock的类关系图

image-1673251212590
image-1673251212590

lock.lock()源码

代码语言:javascript
复制
// 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()源码

代码语言:javascript
复制
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
image-1673251244825
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JUC核心之AQS
    • 重入锁ReentrantLock的初步认识
      • 什么是锁
      • 加锁前后的区别
      • 什么是重入锁
      • 锁的类图
    • AQS是什么
      • ReentrantLock的类关系图
      • lock.lock()源码
      • lock.unlock()源码
      • 原理运行图
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档